[Bf-blender-cvs] [095f016fc07] universal-scene-description: USD import: read skeletons.

Michael Kowalski noreply at git.blender.org
Tue Aug 30 23:07:24 CEST 2022


Commit: 095f016fc07300a6ed30c02144e6100c313faf01
Author: Michael Kowalski
Date:   Tue Aug 30 15:15:42 2022 -0400
Branches: universal-scene-description
https://developer.blender.org/rB095f016fc07300a6ed30c02144e6100c313faf01

USD import: read skeletons.

Added new option to import USD skeletons as Blender
armatures.  Added new USDSkeletonReader class and
updated the mesh import code to optionally create
armature modifiers for meshes bound to skeletons.
Added logic to the mesh reader to allow overriding
the mesh transform to ensure the mesh is aligned
with the authored geom bind transform.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/CMakeLists.txt
M	source/blender/io/usd/intern/usd_capi_import.cc
M	source/blender/io/usd/intern/usd_reader_mesh.cc
M	source/blender/io/usd/intern/usd_reader_mesh.h
A	source/blender/io/usd/intern/usd_reader_skeleton.cc
A	source/blender/io/usd/intern/usd_reader_skeleton.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_reader_xform.cc
M	source/blender/io/usd/intern/usd_reader_xform.h
M	source/blender/io/usd/intern/usd_skel_convert.cc
M	source/blender/io/usd/intern/usd_skel_convert.h
M	source/blender/io/usd/intern/usd_writer_armature.cc
M	source/blender/io/usd/intern/usd_writer_skinned_mesh.cc
M	source/blender/io/usd/intern/usd_writer_transform.cc
M	source/blender/io/usd/intern/usd_writer_transform.h
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 a9f881025c8..8c8eab0f036 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -965,6 +965,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
   const bool import_meshes = RNA_boolean_get(op->ptr, "import_meshes");
   const bool import_blendshapes = RNA_boolean_get(op->ptr, "import_blendshapes");
   const bool import_volumes = RNA_boolean_get(op->ptr, "import_volumes");
+  const bool import_skeletons = RNA_boolean_get(op->ptr, "import_skeletons");
 
   const bool import_subdiv = RNA_boolean_get(op->ptr, "import_subdiv");
 
@@ -1031,6 +1032,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
                                    .import_meshes = import_meshes,
                                    .import_blendshapes = import_blendshapes,
                                    .import_volumes = import_volumes,
+                                   .import_skeletons = import_skeletons,
                                    .prim_path_mask = prim_path_mask,
                                    .import_subdiv = import_subdiv,
                                    .import_instance_proxies = import_instance_proxies,
@@ -1072,6 +1074,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   uiItemR(col, ptr, "import_meshes", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "import_blendshapes", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "import_volumes", 0, NULL, ICON_NONE);
+  uiItemR(col, ptr, "import_skeletons", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "prim_path_mask", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "scale", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "apply_unit_conversion_scale", 0, NULL, ICON_NONE);
@@ -1168,6 +1171,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
   RNA_def_boolean(ot->srna, "import_meshes", true, "Meshes", "");
   RNA_def_boolean(ot->srna, "import_blendshapes", true, "Blend Shapes", "");
   RNA_def_boolean(ot->srna, "import_volumes", true, "Volumes", "");
+  RNA_def_boolean(ot->srna, "import_skeletons", true, "Skeletons", "");
 
   RNA_def_boolean(ot->srna,
                   "import_subdiv",
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 006768c06d6..4a77bb32544 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
   intern/usd_reader_mesh.cc
   intern/usd_reader_nurbs.cc
   intern/usd_reader_prim.cc
+  intern/usd_reader_skeleton.cc
   intern/usd_reader_stage.cc
   intern/usd_reader_volume.cc
   intern/usd_reader_xform.cc
@@ -119,6 +120,7 @@ set(SRC
   intern/usd_reader_mesh.h
   intern/usd_reader_nurbs.h
   intern/usd_reader_prim.h
+  intern/usd_reader_skeleton.h
   intern/usd_reader_stage.h
   intern/usd_reader_volume.h 
   intern/usd_reader_xform.h
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 7c9e403e108..1d005f92116 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -525,6 +525,10 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
     }
   }
 
+  if (data->params.import_skeletons) {
+    archive->process_armature_modifiers();
+  }
+
   data->import_ok = !data->was_canceled;
 
   *progress = 1.0f;
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 7042756a79d..a63a42c31fa 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -37,6 +37,7 @@
 #include <pxr/usd/usdGeom/mesh.h>
 #include <pxr/usd/usdGeom/subset.h>
 #include <pxr/usd/usdShade/materialBindingAPI.h>
+#include <pxr/usd/usdSkel/bindingAPI.h>
 
 #include <iostream>
 
@@ -277,6 +278,10 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
     import_blendshapes(bmain, object_, prim_);
   }
 
+  if (import_params_.import_skeletons) {
+    import_skel_bindings(bmain, object_, prim_);
+  }
+
   USDXformReader::read_object_data(bmain, motionSampleTime);
 }
 
@@ -955,4 +960,127 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
   return active_mesh;
 }
 
+std::string USDMeshReader::get_skeleton_path() const
+{
+  if (!prim_) {
+    return "";
+  }
+
+   pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(prim_);
+
+  if (!skel_api) {
+    return "";
+  }
+
+  if (pxr::UsdSkelSkeleton skel = skel_api.GetInheritedSkeleton()) {
+    return skel.GetPath().GetAsString();
+  }
+
+  return "";
+}
+
+/* Return a local transform to place the mesh in its world bind position.
+ * In some cases, the bind transform and prim world transform might be
+ * be different, in which case we must adjust the local transform
+ * to ensure the mesh is correctly aligned for bininding.  A use
+ * case where this might be needed is if a skel animation is exported
+ * from Blender and both the skeleton and mesh are transformed in Create
+ * or another DCC, without modifying the original mesh bind transform. */
+bool USDMeshReader::get_geom_bind_xform_correction(const pxr::GfMatrix4d &bind_xf,
+                                                   pxr::GfMatrix4d *r_xform,
+                                                   const float time) const
+{
+  if (!r_xform) {
+    return false;
+  }
+
+  pxr::GfMatrix4d world_xf = get_world_matrix(prim_, time);
+
+  if (pxr::GfIsClose(bind_xf, world_xf, .000000001)) {
+    /* The world and bind matrices are equal, so we don't
+     * need to correct the local transfor.  Get the transform
+     * with the standard API.  */
+    pxr::UsdGeomXformable xformable;
+
+    if (use_parent_xform_) {
+      xformable = pxr::UsdGeomXformable(prim_.GetParent());
+    }
+    else {
+      xformable = pxr::UsdGeomXformable(prim_);
+    }
+
+    if (!xformable) {
+      /* This shouldn't happen. */
+      *r_xform = pxr::GfMatrix4d(1.0);
+      return false;
+    }
+
+    bool reset_xform_stack;
+    return xformable.GetLocalTransformation(r_xform, &reset_xform_stack, time);
+  }
+
+  /* If we got here, then the bind transform and prim
+   * world transform differ, so we must adjust the local
+   * transform to ensure the mesh is aligned in the correct
+   * bind position */
+  pxr::GfMatrix4d parent_world_xf(1.0);
+
+  pxr::UsdPrim parent;
+
+  if (use_parent_xform_) {
+    if (prim_.GetParent()) {
+      parent = prim_.GetParent().GetParent();
+    }
+  }
+  else {
+    parent = prim_.GetParent();
+  }
+
+  if (parent) {
+    parent_world_xf = get_world_matrix(parent, time);
+  }
+
+  pxr::GfMatrix4d corrected_local_xf = bind_xf * parent_world_xf.GetInverse();
+  *r_xform = corrected_local_xf;
+
+  return true;
+}
+
+/* Override transform computation to account for the binding
+ * transformation for skinned meshes. */
+bool USDMeshReader::get_local_usd_xform(pxr::GfMatrix4d *r_xform,
+                                        bool *r_is_constant,
+                                        const float time) const
+{
+  if (!r_xform) {
+    return false;
+  }
+
+  if (!import_params_.import_skeletons) {
+    /* Use the standard transform computation, since we are ignoring
+     * skinning data. */
+    return USDXformReader::get_local_usd_xform(r_xform, r_is_constant, time);
+  }
+
+  if (pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(prim_)) {
+    if (skel_api.GetGeomBindTransformAttr().HasAuthoredValue()) {
+      pxr::GfMatrix4d bind_xf;
+      if (skel_api.GetGeomBindTransformAttr().Get(&bind_xf)) {
+        /* Assume that if a bind transform is defined, then the
+         * transform is constant. */
+        if (r_is_constant) {
+          *r_is_constant = true;
+        }
+        return get_geom_bind_xform_correction(bind_xf, r_xform, time);
+      }
+      else {
+        std::cout << "WARNING: couldn't compute geom bind transform for " << prim_.GetPath()
+                  << std::endl;
+      }
+    }
+  }
+
+  return USDXformReader::get_local_usd_xform(r_xform, r_is_constant, time);
+}
+
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index d27082bb3e5..efa8b4bc8da 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -55,6 +55,8 @@ class USDMeshReader : public USDGeomReader {
 
   bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override;
 
+  std::string get_skeleton_path() const;
+
  private:
   void process_normals_vertex_varying(Mesh *mesh);
   void process_normals_face_varying(Mesh *mesh);
@@ -76,6 +78,14 @@ class USDMeshReader : public USDGeomReader {
                         Mesh *mesh,
                         double motionSampleTime,
                         bool new_mesh);
+
+  bool get_local_usd_xform(pxr::GfMatrix4d *r_xform,
+                           bool *r_is_constant,
+                           const float time) const override;
+
+  bool get_geom_bind_xform_correction(const pxr::GfMatrix4d &bind_xf,
+                                      pxr::GfMatrix4d *r_xform,
+                                      const float time) const;
 };
 
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_skeleton.cc b/source/blender/io/usd/intern/usd_reader_skeleton.cc
new file mode 100644
index 00000000000..5c57175de14
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_skeleton.cc
@@ -0,0 +1,373 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list