[Bf-blender-cvs] [b0cb45f2b9f] temp-alembic-exporter-T73363-ms2: Abstract Hierarchy Iterator: allow exporting transforms OR shapes
Sybren A. Stüvel
noreply at git.blender.org
Fri Mar 20 12:36:46 CET 2020
Commit: b0cb45f2b9fef6a794ed15d8b9012b221c2b1b03
Author: Sybren A. Stüvel
Date: Fri Mar 20 11:41:54 2020 +0100
Branches: temp-alembic-exporter-T73363-ms2
https://developer.blender.org/rBb0cb45f2b9fef6a794ed15d8b9012b221c2b1b03
Abstract Hierarchy Iterator: allow exporting transforms OR shapes
The Alembic exporter allows different sampling rates for transforms and
for shapes. This is necessary, for example, to have control over motion
blur: when only using rigid objects, it's enough to export sub-frame
samples of transforms.
===================================================================
M source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
M source/blender/io/usd/intern/abstract_hierarchy_iterator.h
M tests/gtests/usd/abstract_hierarchy_iterator_test.cc
===================================================================
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
index 924ca3e4802..333a0bd74a5 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
@@ -105,7 +105,7 @@ bool AbstractHierarchyWriter::check_is_animated(const HierarchyContext &context)
}
AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph)
- : depsgraph_(depsgraph), writers_()
+ : depsgraph_(depsgraph), writers_(), export_subset_({true, true})
{
}
@@ -132,6 +132,11 @@ void AbstractHierarchyIterator::release_writers()
writers_.clear();
}
+void AbstractHierarchyIterator::set_export_subset(ExportSubset export_subset)
+{
+ export_subset_ = export_subset;
+}
+
std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const
{
return name;
@@ -473,6 +478,7 @@ void AbstractHierarchyIterator::determine_duplication_references(
void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context)
{
AbstractHierarchyWriter *transform_writer = nullptr;
+ bool created = false;
float parent_matrix_inv_world[4][4];
if (parent_context) {
@@ -488,7 +494,8 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont
context->parent_context = parent_context;
// Get or create the transform writer.
- transform_writer = ensure_writer(context, &AbstractHierarchyIterator::create_transform_writer);
+ std::tie(transform_writer, created) = ensure_writer(
+ context, &AbstractHierarchyIterator::create_transform_writer);
if (transform_writer == nullptr) {
// Unable to export, so there is nothing to attach any children to; just abort this entire
// branch of the export hierarchy.
@@ -496,10 +503,12 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont
}
BLI_assert(DEG_is_evaluated_object(context->object));
- /* XXX This can lead to too many XForms being written. For example, a camera writer can refuse
- * to write an orthographic camera. By the time that this is known, the XForm has already been
- * written. */
- transform_writer->write(*context);
+ if (created || export_subset_.transforms) {
+ /* XXX This can lead to too many XForms being written. For example, a camera writer can
+ * refuse to write an orthographic camera. By the time that this is known, the XForm has
+ * already been written. */
+ transform_writer->write(*context);
+ }
if (!context->weak_export) {
make_writers_particle_systems(context);
@@ -532,13 +541,18 @@ void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *
BLI_assert(data_context.is_instance());
}
+ /* Always write upon creation, otherwise depend on which subset is active. */
AbstractHierarchyWriter *data_writer;
- data_writer = ensure_writer(&data_context, &AbstractHierarchyIterator::create_data_writer);
+ bool created;
+ std::tie(data_writer, created) = ensure_writer(&data_context,
+ &AbstractHierarchyIterator::create_data_writer);
if (data_writer == nullptr) {
return;
}
- data_writer->write(data_context);
+ if (created || export_subset_.shapes) {
+ data_writer->write(data_context);
+ }
}
void AbstractHierarchyIterator::make_writers_particle_systems(
@@ -557,16 +571,23 @@ void AbstractHierarchyIterator::make_writers_particle_systems(
hair_context.particle_system = psys;
AbstractHierarchyWriter *writer = nullptr;
+ bool created = false;
switch (psys->part->type) {
case PART_HAIR:
- writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer);
+ std::tie(writer, created) = ensure_writer(&hair_context,
+ &AbstractHierarchyIterator::create_hair_writer);
break;
case PART_EMITTER:
- writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer);
+ std::tie(writer, created) = ensure_writer(
+ &hair_context, &AbstractHierarchyIterator::create_particle_writer);
break;
}
+ if (writer == nullptr) {
+ continue;
+ }
- if (writer != nullptr) {
+ /* Always write upon creation, otherwise depend on which subset is active. */
+ if (created || export_subset_.shapes) {
writer->write(hair_context);
}
}
@@ -593,22 +614,21 @@ AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(const std::string
return it->second;
}
-AbstractHierarchyWriter *AbstractHierarchyIterator::ensure_writer(
+std::pair<AbstractHierarchyWriter *, bool> AbstractHierarchyIterator::ensure_writer(
HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func)
{
AbstractHierarchyWriter *writer = get_writer(context->export_path);
if (writer != nullptr) {
- return writer;
+ return std::make_pair(writer, false);
}
writer = (this->*create_func)(context);
if (writer == nullptr) {
- return nullptr;
+ return std::make_pair(nullptr, false);
}
writers_[context->export_path] = writer;
-
- return writer;
+ return std::make_pair(writer, true);
}
std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path,
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
index f7ec0de1dcd..5e11fed193f 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
@@ -124,6 +124,12 @@ class AbstractHierarchyWriter {
virtual bool check_is_animated(const HierarchyContext &context) const;
};
+/* Determines which subset of the writers actually gets to write. */
+struct ExportSubset {
+ bool transforms : 1;
+ bool shapes : 1;
+};
+
/* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export
* writers. These writers are then called to perform the actual writing to a USD or Alembic file.
*
@@ -152,6 +158,7 @@ class AbstractHierarchyIterator {
ExportPathMap duplisource_export_path_;
Depsgraph *depsgraph_;
WriterMap writers_;
+ ExportSubset export_subset_;
public:
explicit AbstractHierarchyIterator(Depsgraph *depsgraph);
@@ -159,12 +166,21 @@ class AbstractHierarchyIterator {
/* Iterate over the depsgraph, create writers, and tell the writers to write.
* Main entry point for the AbstractHierarchyIterator, must be called for every to-be-exported
- * frame. */
+ * (sub)frame. */
void iterate_and_write();
/* Release all writers. Call after all frames have been exported. */
void release_writers();
+ /* Determine which subset of writers is used for exporting.
+ * Set this before calling iterate_and_write().
+ *
+ * Note that writers are created for each iterated object, regardless of this option. When a
+ * writer is created it will also write the current iteration, to ensure the hierarchy is
+ * complete. The `export_subset` option is only in effect when the writer already existed from a
+ * previous iteration. */
+ void set_export_subset(ExportSubset export_subset_);
+
/* Convert the given name to something that is valid for the exported file format.
* This base implementation is a no-op; override in a concrete subclass. */
virtual std::string make_valid_name(const std::string &name) const;
@@ -198,6 +214,7 @@ class AbstractHierarchyIterator {
void determine_duplication_references(const HierarchyContext *parent_context,
std::string indent);
+ /* These three functions create writers and call their write() method. */
void make_writers(const HierarchyContext *parent_context);
void make_writer_object_data(const HierarchyContext *context);
void make_writers_particle_systems(const HierarchyContext *context);
@@ -210,10 +227,12 @@ class AbstractHierarchyIterator {
typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)(
const HierarchyContext *);
- /* Ensure that a writer exists; if it doesn't, call create_func(context). The create_func
- * function should be one of the create_XXXX_writer(context) functions declared below. */
- AbstractHierarchyWriter *ensure_writer(HierarchyContext *context,
- create_writer_func create_func);
+ /* Ensure that a writer exists; if it doesn't, call create_func(context).
+ *
+ * The create_func function should be one of the create_XXXX_writer(context) functions declared
+ * below. Returns a pair <writer, created>. */
+ std::pair<AbstractHierarchyWriter *, bool> ensure_writer(HierarchyContext *context,
+ create_writer_func create_func);
protected:
/* Construct a valid path for the export file format. This class concatenates by using '/' as a
diff --git a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc
index 375d59863d7..fbb97bd0743 100644
--- a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc
+++ b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc
@@ -200,4 +200,118 @@ TEST_F(USDHierarchyIteratorTest, ExportHierarchyTest)
// The scene has no hair or particle systems.
EXPECT_EQ(0, iterator->hair_writers.size());
EXPECT_EQ(0, iterator->particle_writers.size());
+
+ // On the second iteration, everything should be written as well.
+ // This tests the default value of iterator->export_subset_.
+ iterator->transform_writers.clear();
+ iterator->data_writers.clear();
+ iterator->iterate_and_write();
+ EXPECT_EQ(expected_transforms, iterator->transform_writers);
+ EXPECT_EQ(expected_data, iterator->data_writers);
+}
+
+TEST_F(USDHierarchyIteratorTest, ExportSubsetTest)
+{
+ // The scene has no hair or particle systems, and this is already covered by ExportHierarchyTest,
+ // so not included here. Update this test when hair & particle systems
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list