[Bf-blender-cvs] [8b9275d4330] usd-importer-T81257-merge: USD Import: support instance collections.

makowalski noreply at git.blender.org
Wed Mar 3 16:17:10 CET 2021


Commit: 8b9275d4330d6721e46f02dc0e0f41c585f2807a
Author: makowalski
Date:   Wed Mar 3 00:07:25 2021 -0500
Branches: usd-importer-T81257-merge
https://developer.blender.org/rB8b9275d4330d6721e46f02dc0e0f41c585f2807a

USD Import: support instance collections.

Added an experimental Instancing option to support
importing USD scenegraph instances as Blender
instanced collections.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/CMakeLists.txt
M	source/blender/io/usd/intern/usd_capi.cc
A	source/blender/io/usd/intern/usd_reader_instance.cc
A	source/blender/io/usd/intern/usd_reader_instance.h
M	source/blender/io/usd/intern/usd_reader_stage.cc
M	source/blender/io/usd/intern/usd_reader_stage.h
M	source/blender/io/usd/intern/usd_util.cc
M	source/blender/io/usd/usd.h

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

diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 068def29f70..a1f2d14b606 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -311,6 +311,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
   const bool import_proxy = RNA_boolean_get(op->ptr, "import_proxy");
   const bool import_render = RNA_boolean_get(op->ptr, "import_render");
 
+  const bool use_instancing = RNA_boolean_get(op->ptr, "use_instancing");
+
   int offset = 0;
   int sequence_len = 1;
 
@@ -352,6 +354,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
       import_proxy,
       import_render,
       import_visible_only,
+      use_instancing,
   };
 
   bool ok = USD_import(C, filename, &params, as_background_job);
@@ -437,6 +440,9 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   uiItemR(box, ptr, "import_proxy", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "import_render", 0, NULL, ICON_NONE);
 
+  box = uiLayoutBox(layout);
+  uiItemL(box, IFACE_("Experimental"), ICON_NONE);
+  uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
 }
 
 void WM_OT_usd_import(struct wmOperatorType *ot)
@@ -539,7 +545,8 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
                   true,
                   "Import Instance Proxies",
                   "If enabled, USD instances will be traversed with instance proxies, "
-                  "creating a unique Blender object for each instance");
+                  "creating a unique Blender object for each instance.  Note that "
+                  "this option is ignored if the Instancing option is also checked"  );
 
   RNA_def_boolean(ot->srna,
                   "import_visible_only",
@@ -578,6 +585,14 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
 
   RNA_def_boolean(
     ot->srna, "import_render", true, "Render", "When checked, import final render geometry");
+
+  RNA_def_boolean(
+    ot->srna,
+    "use_instancing",
+    false,
+    "Instancing",
+    "When checked, USD scenegraph instances are imported as collection instances in Blender. "
+    "(Note that point instancers are not yet handled by this option.)");
 }
 
 #endif /* WITH_USD */
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 46c2ac26e94..70a1045be85 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
   intern/usd_reader_camera.cc
   intern/usd_reader_curve.cc
   intern/usd_reader_geom.cc
+  intern/usd_reader_instance.cc
   intern/usd_reader_light.cc
   intern/usd_reader_mesh.cc
   intern/usd_reader_nurbs.cc
@@ -92,6 +93,7 @@ set(SRC
   intern/usd_reader_camera.h
   intern/usd_reader_curve.h
   intern/usd_reader_geom.h
+  intern/usd_reader_instance.h
   intern/usd_reader_light.h
   intern/usd_reader_mesh.h
   intern/usd_reader_nurbs.h
diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc
index e808cba4c64..dd4ca6e28da 100644
--- a/source/blender/io/usd/intern/usd_capi.cc
+++ b/source/blender/io/usd/intern/usd_capi.cc
@@ -19,6 +19,7 @@
 
 #include "usd.h"
 #include "usd_hierarchy_iterator.h"
+#include "usd_reader_instance.h"
 #include "usd_reader_mesh.h"
 #include "usd_reader_prim.h"
 #include "usd_reader_stage.h"
@@ -74,6 +75,8 @@
 #include "usd_reader_prim.h"
 #include "usd_util.h"
 
+#include <iostream>
+
 struct USDStageHandle {
   CacheArchiveHandle base;
 };
@@ -114,6 +117,128 @@ static bool gather_objects_paths(const pxr::UsdPrim &object, ListBase *object_pa
   return true;
 }
 
+/* Create a collection with the given parent and name. */
+static Collection *create_collection(Main *bmain, Collection *parent, const char *name)
+{
+  if (!bmain) {
+    return nullptr;
+  }
+
+  Collection *coll = BKE_collection_add(bmain, parent, name);
+
+  if (coll) {
+    id_fake_user_set(&coll->id);
+    DEG_id_tag_update(&coll->id, ID_RECALC_COPY_ON_WRITE);
+  }
+
+  return coll;
+}
+
+/* Set the instance collection on the given instance reader.
+*  The collection is assigned from the given map based on
+*  the prototype (maser) prim path. */
+static void set_instance_collection(
+  USDInstanceReader *instance_reader,
+  const std::map<pxr::SdfPath, Collection *> &proto_collection_map)
+{
+  if (!instance_reader) {
+    return;
+  }
+
+  pxr::SdfPath proto_path = instance_reader->proto_path();
+
+  std::map<pxr::SdfPath, Collection *>::const_iterator it = proto_collection_map.find(proto_path);
+
+  if (it != proto_collection_map.end()) {
+    instance_reader->set_instance_collection(it->second);
+  }
+  else {
+    std::cerr << "WARNING: Couldn't find prototype collection for " << instance_reader->prim_path()
+      << std::endl;
+  }
+}
+
+/* Create instance collections for the USD instance readers. */
+static void create_proto_collections(
+  Main *bmain,
+  ViewLayer *view_layer,
+  Collection *parent_collection,
+  const USDStageReader::ProtoReaderMap &proto_readers,
+  const std::vector<USDPrimReader *> &readers)
+{
+  Collection *all_protos_collection = create_collection(bmain, parent_collection, "prototypes");
+
+  std::map<pxr::SdfPath, Collection *> proto_collection_map;
+
+  for (const auto &pair : proto_readers) {
+
+    std::string proto_collection_name = pair.first.GetString();
+
+    // TODO(makowalski): Is it acceptable to have slashes in the collection names? Or should we
+    // replace them with another character, like an underscore, as in the following?
+    // std::replace(proto_collection_name.begin(), proto_collection_name.end(), '/', '_');
+
+    Collection *proto_collection = create_collection(
+      bmain, all_protos_collection, proto_collection_name.c_str());
+
+    LayerCollection *proto_lc = BKE_layer_collection_first_from_scene_collection(view_layer,
+      proto_collection);
+    if (proto_lc) {
+      proto_lc->flag |= LAYER_COLLECTION_HIDE;
+    }
+
+    proto_collection_map.insert(std::make_pair(pair.first, proto_collection));
+  }
+
+  // Set the instance collections on the readers, including the prototype
+  // readers, as instancing may be recursive.
+
+  for (const auto &pair : proto_readers) {
+    for (USDPrimReader *reader : pair.second) {
+      if (USDInstanceReader *instance_reader = dynamic_cast<USDInstanceReader *>(reader)) {
+        set_instance_collection(instance_reader, proto_collection_map);
+      }
+    }
+  }
+
+  for (USDPrimReader *reader : readers) {
+    if (USDInstanceReader *instance_reader = dynamic_cast<USDInstanceReader *>(reader)) {
+      set_instance_collection(instance_reader, proto_collection_map);
+    }
+  }
+
+  // Add the prototype objects to the collections.
+  for (const auto &pair : proto_readers) {
+
+    std::map<pxr::SdfPath, Collection *>::const_iterator it = proto_collection_map.find(
+      pair.first);
+
+    if (it == proto_collection_map.end()) {
+      std::cerr << "WARNING: Couldn't find collection when adding objects for prototype "
+        << pair.first << std::endl;
+      continue;
+    }
+
+    for (USDPrimReader *reader : pair.second) {
+      Object *ob = reader->object();
+
+      if (!ob) {
+        continue;
+      }
+
+      Collection *coll = it->second;
+
+      BKE_collection_object_add(bmain, coll, ob);
+
+      DEG_id_tag_update(&coll->id, ID_RECALC_COPY_ON_WRITE);
+      DEG_id_tag_update_ex(bmain,
+        &ob->id,
+        ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION |
+        ID_RECALC_BASE_FLAGS);
+    }
+  }
+}
+
 /* ********************** Export file ********************** */
 
 struct ExportJobData {
@@ -444,9 +569,38 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
   const float size = static_cast<float>(data->readers.size());
   size_t i = 0;
 
+  /* Setup parenthood */
+
+  /* Handle instance prototypes.
+  /* TODO(makowalski): Move this logic inside USDReaderStage? */
+  for (const auto &pair : archive->proto_readers()) {
+
+    for (USDPrimReader *reader : pair.second) {
+
+      if (!reader) {
+        continue;
+      }
+
+      /* TODO(makowalski): Here and below, should we call
+      *  readObjectData() with the actual time? */
+      reader->readObjectData(data->bmain, 0.0);
+
+      Object *ob = reader->object();
+
+      if (!ob) {
+        continue;
+      }
+
+      const USDPrimReader *parent_reader = reader->parent();
+
+      ob->parent = parent_reader ? parent_reader->object() : nullptr;
+
+      // TODO(makowalski): Handle progress update.
+    }
+  }
+
   std::vector<USDPrimReader *>::iterator iter;
 
-  /* Setup parenthood */
   for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
     Object *ob = (*iter)->object();
 
@@ -498,6 +652,19 @@ static void import_endjob(void *customdata)
 
       BKE_id_free_us(data->bmain, ob);
     }
+
+    if (data->archive) {
+      for (const auto &pair : data->archive->proto_readers()) {
+        for (USDPrimReader *reader : pair.second) {
+          Object *ob = reader->object();
+          /* It's possible that cancellation occurred between the creation of
+           * the reader and the creation of the Blender object. */
+          if (ob != NULL) {
+            BKE_id_free_us(data->bmain, ob);
+          }
+        }
+      }
+    }
   }
   else {
     /* Add object to scene. */
@@ -509,6 +676,11 @@ static void import_endjob(void *customdata)
 
     lc = BKE_layer_collection_get_active(view_layer);
 
+    if (data->archive && !data->archive->proto_readers().empty()) {
+      create_proto_collections(
+        data->bmain, view_layer, lc->collection, data->archive->proto_readers(), data->readers);
+    }
+
     for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
       Object *ob = (*iter)->object();
 
@@ -538,6 +710,8 @@ static void import_endjob(void *customdata)
     }
   }
 
+  data->archive->clear_proto_readers(true);
+
   WM_set_locked_interface(data->wm, false);
 
   switch (data->error_code) {
diff --git a/source/blender/io/usd/intern/usd_reader_instance.cc b/source/blender/io/usd/intern/usd_reader_instance.cc
new file mode 100644
index 00000000000..bb0ac3c1e2b
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list