[Bf-blender-cvs] [70852c88ad] temp-sybren-alembic: Alembic: fixed importer

Sybren A. Stüvel noreply at git.blender.org
Fri Feb 24 17:06:03 CET 2017


Commit: 70852c88ad275cdaac4818b3b90c7a8b97225f8b
Author: Sybren A. Stüvel
Date:   Wed Feb 15 17:29:26 2017 +0100
Branches: temp-sybren-alembic
https://developer.blender.org/rB70852c88ad275cdaac4818b3b90c7a8b97225f8b

Alembic: fixed importer

The importer was guessing whether an Alembic IXform object was part of a
child object, or should be represented as an Empty in Blender. By reversing
the order in which objects are visited, the children can now claim their
parent as part of the same object (so IPolyMesh claims its parent IXform
as part of the same Blender object). This results in much less guesswork.

I've also removed similar guesswork from the code that sets parent pointers,
by simply searching for the parent in a hierarchical way, instead of trying
to predict (again) which IXforms were turned into empties.

Also, visit_object() now actually visits the object -- previously it only
visited its children, and assumed the object it was called on was already
handled by a previous call.

===================================================================

M	source/blender/alembic/intern/alembic_capi.cc

===================================================================

diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index d8d017119b..c9f4376316 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -152,7 +152,7 @@ static void gather_objects_paths(const IObject &object, ListBase *object_paths)
 					}
 #if 0
 					else {
-						std::cerr << "Skipping " << child.getFullName() << '\n';
+						std::cerr << "gather_objects_paths(" << object.getFullName() << "): Skipping " << child.getFullName() << '\n';
 					}
 #endif
 				}
@@ -376,114 +376,162 @@ void ABC_export(
 
 /* ********************** Import file ********************** */
 
-static void visit_object(const IObject &object,
+static int visit_object(const IObject &object,
                          std::vector<AbcObjectReader *> &readers,
                          GHash *parent_map,
                          ImportSettings &settings)
 {
 	if (!object.valid()) {
-		return;
+		std::cerr << "  - " << object.getFullName() << ": object is invalid, skipping it and all its children.\n";
+		return false;
 	}
 
-	for (int i = 0; i < object.getNumChildren(); ++i) {
-		IObject child = object.getChild(i);
-
-		if (!child.valid()) {
-			continue;
-		}
+	// The interpretation of data by the children determine the role of this object.
+	// This is especially important for Xform objects, as they can be either part of a Blender object
+	// or a Blender object (empty) themselves.
+	size_t children_claiming_this_object = 0;
+	size_t num_children = object.getNumChildren();
+	BLI_assert((int)true == 1);
+	for (size_t i = 0; i < num_children; ++i) {
+		bool child_claims_this_object = visit_object(object.getChild(i), readers, parent_map, settings);
+		children_claiming_this_object += child_claims_this_object;  // using (int)true == 1
+	}
 
-		AbcObjectReader *reader = NULL;
+	AbcObjectReader *reader = NULL;
 
-		const MetaData &md = child.getMetaData();
+	const MetaData &md = object.getMetaData();
+//	const std::string schema_obj_title = md.get("schemaObjTitle");
+//	std::cerr << "  - " << object.getFullName() << "(" << schema_obj_title << "): ";
 
-		if (IXform::matches(md)) {
-			bool create_xform = false;
+	bool parent_is_part_of_this_object = false;
+	if (!object.getParent()) {
+		// The root itself is not an object we should import.
+	}
+	else if (IXform::matches(md)) {
+		bool create_empty;
 
-			/* Check whether or not this object is a Maya locator, which is
-			 * similar to empties used as parent object in Blender. */
-			if (has_property(child.getProperties(), "locator")) {
-				create_xform = true;
-			}
-			else {
-				/* Avoid creating an empty object if the child of this transform
-				 * is not a transform (that is an empty). */
-				if (child.getNumChildren() == 1) {
-					if (IXform::matches(child.getChild(0).getMetaData())) {
-						create_xform = true;
-					}
-#if 0
-					else {
-						std::cerr << "Skipping " << child.getFullName() << '\n';
-					}
-#endif
-				}
-				else {
-					create_xform = true;
-				}
-			}
+		/* An xform can either be a Blender Object (if it contains a mesh, for exapmle),
+		 * but it can also be an Empty. Its correct translation to Blender's data model
+		 * depends on its children. */
 
-			if (create_xform) {
-				reader = new AbcEmptyReader(child, settings);
-			}
-		}
-		else if (IPolyMesh::matches(md)) {
-			reader = new AbcMeshReader(child, settings);
+		/* Check whether or not this object is a Maya locator, which is
+		 * similar to empties used as parent object in Blender. */
+		if (has_property(object.getProperties(), "locator")) {
+//			std::cerr << "Maya locator; ";
+			create_empty = true;
 		}
-		else if (ISubD::matches(md)) {
-			reader = new AbcSubDReader(child, settings);
-		}
-		else if (INuPatch::matches(md)) {
+		else {
+			if (0 < children_claiming_this_object && children_claiming_this_object < num_children) {
+				std::cerr << children_claiming_this_object
+				          << " of its " << num_children << " children used this Xform for themselves, "
+				          << "which is inconsistent!" << std::endl;
+				create_empty = true;
+			}
+//			if (children_claiming_this_object > 0) {
+//				std::cerr << children_claiming_this_object << " of its " << num_children
+//				          << " children used this Xform for themselves, so not creating empty\n";
+//			}
+//			else {
+//				std::cerr << "None of its " << num_children
+//				          << " children used this Xform for themselves, creating empty\n";
+//			}
+			create_empty = children_claiming_this_object == 0;
+		}
+
+		if (create_empty) {
+			reader = new AbcEmptyReader(object, settings);
+//			std::cerr << "created an AbcEmptyReader "
+//			          << reader->object_name()
+//			          << " with data " << reader->data_name();
+		}
+	}
+	else if (IPolyMesh::matches(md)) {
+		reader = new AbcMeshReader(object, settings);
+		parent_is_part_of_this_object = true;
+//		std::cerr << "created an AbcMeshReader "
+//		          << reader->object_name()
+//		          << " with data " << reader->data_name();
+	}
+	else if (ISubD::matches(md)) {
+		reader = new AbcSubDReader(object, settings);
+		parent_is_part_of_this_object = true;
+//		std::cerr << "created an AbcSubDReader "
+//		          << reader->object_name()
+//		          << " with data " << reader->data_name();
+	}
+	else if (INuPatch::matches(md)) {
 #ifdef USE_NURBS
-			/* TODO(kevin): importing cyclic NURBS from other software crashes
-			 * at the moment. This is due to the fact that NURBS in other
-			 * software have duplicated points which causes buffer overflows in
-			 * Blender. Need to figure out exactly how these points are
-			 * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
-			 * Until this is fixed, disabling NURBS reading. */
-			reader = new AbcNurbsReader(child, settings);
+		/* TODO(kevin): importing cyclic NURBS from other software crashes
+		 * at the moment. This is due to the fact that NURBS in other
+		 * software have duplicated points which causes buffer overflows in
+		 * Blender. Need to figure out exactly how these points are
+		 * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+		 * Until this is fixed, disabling NURBS reading. */
+		reader = new AbcNurbsReader(object, settings);
+		parent_is_part_of_this_object = true;
 #endif
-		}
-		else if (ICamera::matches(md)) {
-			reader = new AbcCameraReader(child, settings);
-		}
-		else if (IPoints::matches(md)) {
-			reader = new AbcPointsReader(child, settings);
-		}
-		else if (IMaterial::matches(md)) {
-			/* Pass for now. */
-		}
-		else if (ILight::matches(md)) {
-			/* Pass for now. */
-		}
-		else if (IFaceSet::matches(md)) {
-			/* Pass, those are handled in the mesh reader. */
-		}
-		else if (ICurves::matches(md)) {
-			reader = new AbcCurveReader(child, settings);
-		}
-		else {
-			assert(false);
-		}
+	}
+	else if (ICamera::matches(md)) {
+		reader = new AbcCameraReader(object, settings);
+		parent_is_part_of_this_object = true;
+//		std::cerr << "created an AbcCameraReader "
+//		          << reader->object_name()
+//		          << " with data " << reader->data_name();
+	}
+	else if (IPoints::matches(md)) {
+		reader = new AbcPointsReader(object, settings);
+		parent_is_part_of_this_object = true;
+//		std::cerr << "created an AbcPointsReader "
+//		          << reader->object_name()
+//		          << " with data " << reader->data_name();
+	}
+	else if (IMaterial::matches(md)) {
+		/* Pass for now. */
+//		std::cerr << "skipping IMaterial objects";
+	}
+	else if (ILight::matches(md)) {
+		/* Pass for now. */
+//		std::cerr << "skipping ILight objects";
+	}
+	else if (IFaceSet::matches(md)) {
+		/* Pass, those are handled in the mesh reader. */
+//		std::cerr << "skipping IFaceSet objects";
+	}
+	else if (ICurves::matches(md)) {
+		reader = new AbcCurveReader(object, settings);
+		parent_is_part_of_this_object = true;
+//		std::cerr << "created an AbcCurveReader "
+//		          << reader->object_name()
+//		          << " with data " << reader->data_name();
+	}
+	else {
+		std::cerr << "object is of unsupported schema type "
+		          << "'" << object.getMetaData().get("schemaObjTitle") << "'"
+		          << std::endl;
+		BLI_assert(false);
+		return false;
+	}
 
-		if (reader) {
-			readers.push_back(reader);
-			reader->incref();
+//	std::cerr << std::endl;
 
-			AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
-			                                  MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+	if (reader) {
+		readers.push_back(reader);
+		reader->incref();
 
-			BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+		AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+		                                  MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
 
-			BLI_addtail(&settings.cache_file->object_paths, abc_path);
+		BLI_strncpy(abc_path->path, object.getFullName().c_str(), PATH_MAX);
 
-			/* Cast to `void *` explicitly to avoid compiler errors because it
-			 * is a `const char *` which the compiler cast to `const void *`
-			 * instead of the expected `void *`. */
-			BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
-		}
+		BLI_addtail(&settings.cache_file->object_paths, abc_path);
 
-		visit_object(child, readers, parent_map, settings);
+		/* Cast to `void *` explicitly to avoid compiler errors because it
+		 * is a `const char *` which the compiler cast to `const void *`
+		 * instead of the expected `void *`. */
+		BLI_ghash_insert(parent_map, (void *)object.getFullName().c_str(), reader);
 	}
+
+	return parent_is_part_of_this_object;
 }
 
 enum {
@@ -576,7 +624,6 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
 	data->parent_map = BLI_ghash_str_new("alembic parent ghash");
 
 	/* Parse Alembic Archive. */
-
 	visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
 
 	if (G.is_break) {
@@ -606,6 +653,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
 			min_time = std::min(min_time, reader->minTime());
 			max_time = std::max(max_time, reader->maxTime());
 		}
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list