[Bf-blender-cvs] [59f07242bb3] sybren-usd: USD: Initial support for exporting animated data

Sybren A. Stüvel noreply at git.blender.org
Thu Jun 27 12:25:13 CEST 2019


Commit: 59f07242bb38cf6d9358df6fe7f999320ad4665b
Author: Sybren A. Stüvel
Date:   Tue Jun 25 15:03:38 2019 +0200
Branches: sybren-usd
https://developer.blender.org/rB59f07242bb38cf6d9358df6fe7f999320ad4665b

USD: Initial support for exporting animated data

Mesh and transform animation are now written when passing `animation=True`
to the export operator. There is no inspection of whether an object is
actually animated or not, so this will likely export too much information
(each mesh is written for each frame in the scene).

The administration of which timecode to use for the export is left to the
file-format-specific concrete subclasses of `AbstractHierarchyIterator`;
the abstract iterator itself doesn't know anything about the passage of
time.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/usd/intern/abstract_hierarchy_iterator.cc
M	source/blender/usd/intern/abstract_hierarchy_iterator.h
M	source/blender/usd/intern/usd_capi.cc
M	source/blender/usd/intern/usd_exporter_context.h
M	source/blender/usd/intern/usd_hierarchy_iterator.cc
M	source/blender/usd/intern/usd_hierarchy_iterator.h
M	source/blender/usd/intern/usd_writer_abstract.cc
M	source/blender/usd/intern/usd_writer_abstract.h
M	source/blender/usd/intern/usd_writer_mesh.cc
M	source/blender/usd/intern/usd_writer_mesh.h
M	source/blender/usd/intern/usd_writer_transform.cc
M	source/blender/usd/intern/usd_writer_transform.h
M	source/blender/usd/usd.h

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

diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 8764e8fef1e..97459b94c24 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -84,10 +84,12 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
   const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
   const bool selected_objects_only = RNA_boolean_get(op->ptr, "selected_objects_only");
   const bool visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only");
+  const bool animation = RNA_boolean_get(op->ptr, "animation");
 
   struct USDExportParams params = {
-      .selected_objects_only = selected_objects_only,
-      .visible_objects_only = visible_objects_only,
+      animation,
+      selected_objects_only,
+      visible_objects_only,
   };
 
   bool ok = USD_export(scene, C, filename, &params, as_background_job);
@@ -111,17 +113,24 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
   RNA_def_boolean(ot->srna,
                   "selected_objects_only",
                   false,
-                  "Only export selected objects",
+                  "Only Export Selected Objects",
                   "Only selected objects are exported. Unselected parents of selected objects are "
                   "exported as empty transform.");
 
   RNA_def_boolean(ot->srna,
                   "visible_objects_only",
                   false,
-                  "Only export visible objects",
+                  "Only Export Visible Objects",
                   "Only visible objects are exported. Invisible parents of visible objects are "
                   "exported as empty transform.");
 
+  RNA_def_boolean(ot->srna,
+                  "animation",
+                  false,
+                  "Export Animation",
+                  "When true, the render frame range is exported. When false, only the current "
+                  "frame is exported.");
+
   RNA_def_boolean(
       ot->srna,
       "as_background_job",
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
index 4af2c93e83b..11565b5fd41 100644
--- a/source/blender/usd/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
@@ -6,6 +6,7 @@ extern "C" {
 #include "BKE_anim.h"
 
 #include "BLI_assert.h"
+#include "BLI_math_matrix.h"
 
 #include "DNA_ID.h"
 #include "DNA_layer_types.h"
@@ -89,7 +90,7 @@ void AbstractHierarchyIterator::iterate()
           export_parent = object;
         }
 
-        visit_object(link->ob, export_parent, false);
+        visit_dupli_object(link, export_parent, false);
       }
     }
 
@@ -124,6 +125,51 @@ void AbstractHierarchyIterator::iterate()
   // For debug: print the export paths.
   // printf("====== Export paths:\n");
   make_writers(nullptr, "", nullptr);
+
+  export_graph.clear();
+}
+
+void AbstractHierarchyIterator::visit_object(Object *object,
+                                             Object *export_parent,
+                                             bool weak_export)
+{
+  HierarchyContext context;
+  context.object = object;
+  context.export_parent = export_parent;
+  context.weak_export = weak_export;
+  context.export_path = "";
+  context.parent_writer = nullptr;
+  // TODO(Sybren): avoid creating too many copies of the matrix.
+  copy_m4_m4(context.matrix_world, object->obmat);
+
+  export_graph[export_parent].insert(context);
+
+  // std::string export_parent_name = export_parent ? get_object_name(export_parent) : "/";
+  // printf("    OB %30s %p (parent=%s %p; xform-only=%s; instance=%s; world x = %f)\n",
+  //        get_object_name(object).c_str(),
+  //        object,
+  //        export_parent_name.c_str(),
+  //        export_parent,
+  //        context.weak_export ? "\033[31;1mtrue\033[0m" : "false",
+  //        context.object->base_flag & BASE_FROM_DUPLI ? "\033[35;1mtrue\033[0m" :
+  //                                                      "\033[30;1mfalse\033[0m",
+  //        context.matrix_world[3][0]);
+}
+
+void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
+                                                   Object *export_parent,
+                                                   bool weak_export)
+{
+  HierarchyContext context;
+  context.object = dupli_object->ob;
+  context.export_parent = export_parent;
+  context.weak_export = weak_export;
+  context.export_path = "";
+  context.parent_writer = nullptr;
+  // TODO(Sybren): avoid creating too many copies of the matrix.
+  copy_m4_m4(context.matrix_world, dupli_object->mat);
+
+  export_graph[export_parent].insert(context);
 }
 
 static bool prune_the_weak(const HierarchyContext &context,
@@ -190,7 +236,7 @@ void AbstractHierarchyIterator::make_writers(Object *parent_object,
     }
 
     BLI_assert(DEG_is_evaluated_object(context.object));
-    xform_writer->write(context.object);
+    xform_writer->write(context);
 
     // Get or create the object data writer, but only if it is needed.
     if (!context.weak_export && context.object->data != nullptr) {
@@ -203,7 +249,7 @@ void AbstractHierarchyIterator::make_writers(Object *parent_object,
 
       data_writer = ensure_data_writer(context);
       if (data_writer != nullptr) {
-        data_writer->write(context.object);
+        data_writer->write(context);
       }
     }
 
@@ -247,35 +293,6 @@ bool AbstractHierarchyIterator::should_export_object(const Object * /*object*/)
   return true;
 }
 
-void AbstractHierarchyIterator::visit_object(Object *object,
-                                             Object *export_parent,
-                                             bool weak_export)
-{
-  BLI_assert(DEG_is_evaluated_object(object));
-  BLI_assert(export_parent == nullptr || DEG_is_evaluated_object(export_parent));
-
-  HierarchyContext context = {
-      .object = object,
-      .export_parent = export_parent,
-      .weak_export = weak_export,
-
-      // Will be determined during the writer creation:
-      .export_path = "",
-      .parent_writer = nullptr,
-  };
-  export_graph[export_parent].insert(context);
-
-  // std::string export_parent_name = export_parent ? get_object_name(export_parent) : "/";
-  // printf("    OB %30s %p (parent=%s %p; xform-only=%s; instance=%s)\n",
-  //        get_object_name(object).c_str(),
-  //        object,
-  //        export_parent_name.c_str(),
-  //        export_parent,
-  //        context.weak_export ? "\033[31;1mtrue\033[0m" : "false",
-  //        context.object->base_flag & BASE_FROM_DUPLI ? "\033[35;1mtrue\033[0m" :
-  //                                                      "\033[30;1mfalse\033[0m");
-}
-
 AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(const std::string &name)
 {
   WriterMap::iterator it = writers.find(name);
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.h b/source/blender/usd/intern/abstract_hierarchy_iterator.h
index c9cb5844845..8d66db978ba 100644
--- a/source/blender/usd/intern/abstract_hierarchy_iterator.h
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.h
@@ -12,17 +12,13 @@ struct ID;
 struct Object;
 struct ViewLayer;
 
-class AbstractHierarchyWriter {
- public:
-  virtual void write(Object *object_eval) = 0;
-  // TODO: add function like unused_during_iteration() that's called when a writer was previously
-  // created, but wasn't used this iteration.
-};
+class AbstractHierarchyWriter;
 
 struct HierarchyContext {
   /* Determined during hierarchy iteration: */
   Object *object;
   Object *export_parent;
+  float matrix_world[4][4];
 
   // When true, the object will be exported only as transform, and only if is an ancestor of a
   // non-weak child.
@@ -39,6 +35,13 @@ struct HierarchyContext {
   }
 };
 
+class AbstractHierarchyWriter {
+ public:
+  virtual void write(HierarchyContext &context) = 0;
+  // TODO: add function like unused_during_iteration() that's called when a writer was previously
+  // created, but wasn't used this iteration.
+};
+
 class AbstractHierarchyIterator {
  public:
   typedef std::map<std::string, AbstractHierarchyWriter *> WriterMap;
@@ -60,6 +63,7 @@ class AbstractHierarchyIterator {
 
  private:
   void visit_object(Object *object, Object *export_parent, bool weak_export);
+  void visit_dupli_object(DupliObject *dupli_object, Object *export_parent, bool weak_export);
   void prune_export_graph();
 
   void make_writers(Object *parent_object,
diff --git a/source/blender/usd/intern/usd_capi.cc b/source/blender/usd/intern/usd_capi.cc
index 906b0de8523..398379820b4 100644
--- a/source/blender/usd/intern/usd_capi.cc
+++ b/source/blender/usd/intern/usd_capi.cc
@@ -102,10 +102,32 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
     pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filename);
     usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
 
+    // Set up the stage for animated data.
+    if (data->params.do_animation) {
+      usd_stage->SetTimeCodesPerSecond(FPS);
+      usd_stage->SetStartTimeCode(scene->r.sfra);
+      usd_stage->SetEndTimeCode(scene->r.efra);
+    }
+
     USDHierarchyIterator iter(data->depsgraph, usd_stage, data->params);
 
-    // This should be done for every frame, when exporting animation:
-    iter.iterate();
+    if (data->params.do_animation) {
+      for (float frame = scene->r.sfra; frame < scene->r.efra; frame++) {
+        *progress = 0.09 * frame;
+
+        printf("\033[35;1mFRAME\033[0m %f\n", frame);
+        // Update the scene for the next frame to render.
+        scene->r.cfra = static_cast<int>(frame);
+        scene->r.subframe = frame - scene->r.cfra;
+        BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
+
+        iter.set_export_frame(frame);
+        iter.iterate();
+      }
+    }
+    else {
+      iter.iterate();
+    }
 
     iter.release_writers();
     usd_stage->GetRootLayer()->Save();
diff --git a/source/blender/usd/intern/usd_exporter_context.h b/source/blender/usd/intern/usd_exporter_context.h
index c4e7178d108..5483d6f49ed 100644
--- a/source/blender/usd/intern

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list