[Bf-blender-cvs] [fa2de72f868] universal-scene-description: USD export: convert shapekeys to blendshapes.

Michael Kowalski noreply at git.blender.org
Wed Jul 27 03:10:59 CEST 2022


Commit: fa2de72f868507dda4dc4e6eed6bc573128e9d37
Author: Michael Kowalski
Date:   Tue Jul 26 21:08:59 2022 -0400
Branches: universal-scene-description
https://developer.blender.org/rBfa2de72f868507dda4dc4e6eed6bc573128e9d37

USD export: convert shapekeys to blendshapes.

Added option to export shapekeys as UdsSkel blendshapes.
Implemented a new USDBlendShapeMeshWriter class to export
meshes that have shapekeys defined.  Currently, only relative
shapekeys are converted to blendshapes.  Absolute shapekeys
are exported as deformed meshes.  The current implementation
doesn't handle shapekeys on meshes bound to armatures that are
expored as skinned meshes.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/CMakeLists.txt
M	source/blender/io/usd/intern/usd_exporter_context.h
M	source/blender/io/usd/intern/usd_hierarchy_iterator.cc
A	source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
A	source/blender/io/usd/intern/usd_writer_blendshape_mesh.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 defcdba3a39..1cfb3c1e1cc 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -301,6 +301,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
 
   const bool relative_paths = RNA_boolean_get(op->ptr, "relative_paths");
 
+  const bool export_blendshapes = RNA_boolean_get(op->ptr, "export_blendshapes");
+
   struct USDExportParams params = {RNA_int_get(op->ptr, "start"),
                                    RNA_int_get(op->ptr, "end"),
                                    export_animation,
@@ -356,7 +358,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
                                    export_armatures,
                                    xform_op_mode,
                                    fix_skel_root,
-                                   overwrite_textures};
+                                   overwrite_textures,
+                                   export_blendshapes};
 
   /* Take some defaults from the scene, if not specified explicitly. */
   Scene *scene = CTX_data_scene(C);
@@ -457,6 +460,7 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op)
   uiItemR(box, ptr, "export_hair", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "export_particles", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "export_armatures", 0, NULL, ICON_NONE);
+  uiItemR(box, ptr, "export_blendshapes", 0, NULL, ICON_NONE);
 
   box = uiLayoutBox(layout);
   uiItemL(box, IFACE_("Stage Options:"), ICON_SCENE_DATA);
@@ -657,6 +661,12 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
                   "Armatures (Experimental)",
                   "Export armatures and skinned meshes");
 
+  RNA_def_boolean(ot->srna,
+                  "export_blendshapes",
+                  false,
+                  "Blend Shapes",
+                  "Export shape keys as USD blend shapes");
+
   RNA_def_boolean(ot->srna,
                   "use_instancing",
                   false,
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 836455e9ba9..888b7cd1055 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -87,6 +87,7 @@ set(SRC
 
   intern/usd_writer_abstract.cc
   intern/usd_writer_armature.cc
+  intern/usd_writer_blendshape_mesh.cc
   intern/usd_writer_camera.cc
   intern/usd_writer_curve.cc
   intern/usd_writer_hair.cc
@@ -124,6 +125,7 @@ set(SRC
   
   intern/usd_writer_abstract.h
   intern/usd_writer_armature.h
+  intern/usd_writer_blendshape_mesh.h
   intern/usd_writer_camera.h
   intern/usd_writer_curve.h
   intern/usd_writer_hair.h
diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h
index a636d849296..3324ac86fa8 100644
--- a/source/blender/io/usd/intern/usd_exporter_context.h
+++ b/source/blender/io/usd/intern/usd_exporter_context.h
@@ -21,6 +21,11 @@ struct USDExporterContext {
   const pxr::SdfPath usd_path;
   const USDHierarchyIterator *hierarchy_iterator;
   const USDExportParams &export_params;
+
+  template<typename T> T usd_define_or_over(pxr::SdfPath path) const
+  {
+    return (export_params.export_as_overs) ? T(stage->OverridePrim(path)) : T::Define(stage, path);
+  }
 };
 
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
index 902a294727c..5cb7ac059f4 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
@@ -5,6 +5,7 @@
 #include "usd_hierarchy_iterator.h"
 #include "usd_writer_abstract.h"
 #include "usd_writer_armature.h"
+#include "usd_writer_blendshape_mesh.h"
 #include "usd_writer_camera.h"
 #include "usd_writer_curve.h"
 #include "usd_writer_hair.h"
@@ -86,9 +87,17 @@ USDExporterContext USDHierarchyIterator::create_usd_export_context(const Hierarc
   pxr::SdfPath prim_path = pxr::SdfPath(std::string(params_.root_prim_path) +
                                         context->export_path);
   // TODO: Somewhat of a workaround. There could be a better way to incoporate this...
-  bool can_merge_with_xform = !(
-      this->params_.export_armatures &&
-      (is_skinned_mesh(context->object) || context->object->type == OB_ARMATURE));
+
+  bool can_merge_with_xform = true;
+  if (this->params_.export_armatures &&
+      (is_skinned_mesh(context->object) || context->object->type == OB_ARMATURE)) {
+    can_merge_with_xform = false;
+  }
+
+  if (this->params_.export_blendshapes && is_blendshape_mesh(context->object)) {
+    can_merge_with_xform = false;
+  }
+
   if (can_merge_with_xform && mergeTransformAndShape)
     prim_path = prim_path.GetParentPath();
   return USDExporterContext{bmain_, depsgraph_, stage_, prim_path, this, params_};
@@ -102,6 +111,10 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_transform_writer(
     return new USDSkelRootWriter(create_usd_export_context(context));
   }
 
+  if (this->params_.export_blendshapes && is_blendshape_mesh(context->object)) {
+    return new USDSkelRootWriter(create_usd_export_context(context));
+  }
+
   return new USDTransformWriter(create_usd_export_context(context));
 }
 
@@ -122,6 +135,10 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const Hierarch
             is_skinned_mesh(context->object)) {
           data_writer = new USDSkinnedMeshWriter(usd_export_context);
         }
+        else if (usd_export_context.export_params.export_blendshapes &&
+            is_blendshape_mesh(context->object)) {
+          data_writer = new USDBlendShapeMeshWriter(usd_export_context);
+        }
         else {
           data_writer = new USDMeshWriter(usd_export_context);
         }
diff --git a/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc b/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
new file mode 100644
index 00000000000..d4dd84c44be
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
@@ -0,0 +1,370 @@
+/*
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 NVIDIA Corporation.
+ * All rights reserved.
+ */
+#include "usd_writer_blendshape_mesh.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/base/gf/matrix4d.h>
+#include <pxr/base/gf/matrix4f.h>
+#include <pxr/usd/usdGeom/mesh.h>
+#include <pxr/usd/usdSkel/animation.h>
+#include <pxr/usd/usdSkel/blendShape.h>
+
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_math_vector.h"
+
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+
+#include <string>
+
+namespace usdtokens {
+static const pxr::TfToken Anim("Anim", pxr::TfToken::Immortal);
+static const pxr::TfToken Skel("Skel", pxr::TfToken::Immortal);
+static const pxr::TfToken joint1("joint1", pxr::TfToken::Immortal);
+}  // namespace usdtokens
+
+namespace blender::io::usd {
+
+static pxr::VtFloatArray get_blendshape_weights(const Key *key)
+{
+  pxr::VtFloatArray weights;
+
+  LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
+    if (kb == key->block.first) {
+      // Skip the first key, which is the basis.
+      continue;
+    }
+    weights.push_back(kb->curval);
+  }
+
+  return weights;
+}
+
+static const Key *get_shape_key(Object *obj)
+{
+  if (!(obj && obj->data)) {
+    return nullptr;
+  }
+
+  if (obj->type != OB_MESH) {
+    return nullptr;
+  }
+
+  const Mesh *mesh = static_cast<Mesh *>(obj->data);
+
+  return mesh->key;
+}
+
+static void print_blendshape_info(Object *obj)
+{
+  const Key *key = get_shape_key(obj);
+
+  if (!key) {
+    return;
+  }
+
+  printf("have shape key\n");
+  const int num_keys = key->totkey;
+  printf("num keys %d\n", num_keys);
+  printf("type %d\n", key->type);
+  printf("ctime: %f\n", key->ctime);
+  // BKE_keyblock_convert_to_mesh()
+  // BKE_keyblock_mesh_calc_normals()
+  // BKE_keyblock_element_count_from_shape()
+  LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
+    printf("%s %f %f\n", kb->name, kb->curval, kb->pos);
+
+  }
+
+  printf("anim pointer %p\n", key->adt);
+}
+
+bool is_blendshape_mesh(Object *obj)
+{
+  const Key *key = get_shape_key(obj);
+
+  return key && key->totkey > 0 && key->type == KEY_RELATIVE;
+}
+
+USDBlendShapeMeshWriter::USDBlendShapeMeshWriter(const USDExporterContext &ctx) : USDMeshWriter(ctx)
+{
+}
+
+void USDBlendShapeMeshWriter::do_write(HierarchyContext &context)
+{
+  if (!this->frame_has_been_written_) {
+    /* Even though this writer is potentially animated
+     * because it may have animating blendshape weights,
+     * the mesh is never animated.  Setting the is_animated_
+     * varialbe to false before writing the mesh prevents
+     * unwanted time samples for mesh properties from being
+     * written.  Hopefully, there could be nicer way to do this. */
+    bool prev_is_animated = is_animated_;
+    is_animated_ = false;
+    try {
+      USDGenericMeshWriter::do_write(context);
+      is_animated_ = prev_is_animated;
+    }
+    catch (...) {
+      is_animated_ = prev_is_animated;
+      throw;
+    }
+  }
+
+  /* A blendshape writer might be created even if
+   * there are no blendshapes, so check that blendshapes
+   * exist before continuting. */
+  if (!is_blendshape_mesh(context.object)) {
+    return;
+  }
+
+  pxr::UsdStageRefPtr

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list