[Bf-blender-cvs] [833df7ebc1e] universal-scene-description: USD import blendshapes.

Michael Kowalski noreply at git.blender.org
Fri Aug 12 01:14:00 CEST 2022


Commit: 833df7ebc1ef7aecf84b412240162818e5c578e7
Author: Michael Kowalski
Date:   Wed Aug 10 23:19:57 2022 -0400
Branches: universal-scene-description
https://developer.blender.org/rB833df7ebc1ef7aecf84b412240162818e5c578e7

USD import blendshapes.

Importing USD blendshapes as shapekeys and creating
animation curves for animated blendshape weights.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/CMakeLists.txt
M	source/blender/io/usd/intern/usd_reader_mesh.cc
A	source/blender/io/usd/intern/usd_skel_convert.cc
A	source/blender/io/usd/intern/usd_skel_convert.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 1cfb3c1e1cc..a9f881025c8 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -963,6 +963,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
   const bool import_lights = RNA_boolean_get(op->ptr, "import_lights");
   const bool import_materials = RNA_boolean_get(op->ptr, "import_materials");
   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_subdiv = RNA_boolean_get(op->ptr, "import_subdiv");
@@ -1028,6 +1029,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
                                    .import_lights = import_lights,
                                    .import_materials = import_materials,
                                    .import_meshes = import_meshes,
+                                   .import_blendshapes = import_blendshapes,
                                    .import_volumes = import_volumes,
                                    .prim_path_mask = prim_path_mask,
                                    .import_subdiv = import_subdiv,
@@ -1068,6 +1070,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   uiItemR(col, ptr, "import_lights", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "import_materials", 0, NULL, ICON_NONE);
   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(box, ptr, "prim_path_mask", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "scale", 0, NULL, ICON_NONE);
@@ -1163,6 +1166,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
   RNA_def_boolean(ot->srna, "import_lights", true, "Lights", "");
   RNA_def_boolean(ot->srna, "import_materials", true, "Materials", "");
   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,
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 888b7cd1055..006768c06d6 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
   intern/usd_common.cc
   intern/usd_hierarchy_iterator.cc
   intern/usd_light_convert.cc
+  intern/usd_skel_convert.cc
 
   intern/usd_reader_camera.cc
   intern/usd_reader_curve.cc
@@ -107,6 +108,7 @@ set(SRC
   intern/usd_exporter_context.h
   intern/usd_hierarchy_iterator.h
   intern/usd_light_convert.h
+  intern/usd_skel_convert.h
 
   intern/usd_reader_camera.h
   intern/usd_reader_curve.h
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 329f2a7bd03..7042756a79d 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -5,6 +5,7 @@
 
 #include "usd_reader_mesh.h"
 #include "usd_reader_material.h"
+#include "usd_skel_convert.h"
 
 #include "BKE_customdata.h"
 #include "BKE_main.h"
@@ -272,6 +273,10 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
     }
   }
 
+  if (import_params_.import_blendshapes) {
+    import_blendshapes(bmain, object_, prim_);
+  }
+
   USDXformReader::read_object_data(bmain, motionSampleTime);
 }
 
diff --git a/source/blender/io/usd/intern/usd_skel_convert.cc b/source/blender/io/usd/intern/usd_skel_convert.cc
new file mode 100644
index 00000000000..41df30f3f28
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_skel_convert.cc
@@ -0,0 +1,353 @@
+/*
+ * 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_skel_convert.h"
+
+#include "usd.h"
+
+#include <pxr/usd/usdSkel/animation.h>
+#include <pxr/usd/usdSkel/blendShape.h>
+#include <pxr/usd/usdSkel/bindingAPI.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 "BKE_main.h"
+#include "BKE_scene.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_fcurve.h"
+#include "ED_keyframing.h"
+
+#include <string>
+#include <vector>
+
+namespace usdtokens {
+// Attribute names.
+//static const pxr::TfToken color("color", pxr::TfToken::Immortal);
+}  // namespace usdtokens
+
+namespace {
+
+FCurve *create_fcurve(int array_index, const char *rna_path)
+{
+  FCurve *fcu = BKE_fcurve_create();
+  fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
+  fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+  fcu->array_index = array_index;
+  return fcu;
+}
+
+void add_bezt(FCurve *fcu,
+              float frame,
+              float value,
+              eBezTriple_Interpolation ipo = BEZT_IPO_LIN)
+{
+  BezTriple bez;
+  memset(&bez, 0, sizeof(BezTriple));
+  bez.vec[1][0] = frame;
+  bez.vec[1][1] = value;
+  bez.ipo = ipo; /* use default interpolation mode here... */
+  bez.f1 = bez.f2 = bez.f3 = SELECT;
+  bez.h1 = bez.h2 = HD_AUTO;
+  insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
+  BKE_fcurve_handles_recalc(fcu);
+}
+
+}  // End anonymous namespace.
+
+namespace blender::io::usd {
+
+void test_create_shapekeys(Main *bmain, Object *obj)
+{
+  if (!(obj && obj->data && obj->type == OB_MESH)) {
+    return;
+  }
+
+  Mesh *mesh = static_cast<Mesh *>(obj->data);
+
+  /* insert key to source mesh */
+  Key *key = BKE_key_add(bmain, (ID *)mesh);
+  key->type = KEY_RELATIVE;
+
+  mesh->key = key;
+
+  /* insert basis key */
+  KeyBlock *kb = BKE_keyblock_add(key, "Basis");
+  BKE_keyblock_convert_from_mesh(mesh, key, kb);
+
+  kb = BKE_keyblock_add(key, "Key1");
+  BKE_keyblock_convert_from_mesh(mesh, key, kb);
+
+  float offsets[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+  BKE_keyblock_update_from_offset(obj, kb, (float(*)[3])&offsets);
+
+  bAction *act = ED_id_action_ensure(bmain, (ID *)&key->id);
+
+  FCurve *fcu = create_fcurve(0, "key_blocks[\"Key1\"].value");
+  fcu->totvert = 3;
+
+  add_bezt(fcu, 0.f, 0.f);
+  add_bezt(fcu, 30.f, 1.f);
+  add_bezt(fcu, 60.f, 0.3f);
+
+  BLI_addtail(&act->curves, fcu);
+}
+
+void import_blendshapes(Main *bmain, Object *obj, pxr::UsdPrim prim)
+{
+  if (!(obj && obj->data && obj->type == OB_MESH && prim)) {
+    return;
+  }
+
+  pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(prim);
+
+  if (!skel_api) {
+    return;
+  }
+
+  if (!skel_api.GetBlendShapeTargetsRel().HasAuthoredTargets()) {
+    return;
+  }
+
+  pxr::SdfPathVector targets;
+  if (!skel_api.GetBlendShapeTargetsRel().GetTargets(&targets)) {
+    std::cout << "Couldn't get blendshape targets for prim " << prim.GetPath() << std::endl;
+    return;
+  }
+
+  if (targets.empty()) {
+    return;
+  }
+
+  if (!skel_api.GetBlendShapesAttr().HasAuthoredValue()) {
+    return;
+  }
+
+  pxr::VtTokenArray blendshapes;
+  if (!skel_api.GetBlendShapesAttr().Get(&blendshapes)) {
+    return;
+  }
+
+  if (blendshapes.empty()) {
+    return;
+  }
+
+  if (targets.size() != blendshapes.size()) {
+    std::cout << "Number of blendshapes doesn't match number of blendshape targets for prim " << prim.GetPath() << std::endl;
+    return;
+  }
+
+  Mesh *mesh = static_cast<Mesh *>(obj->data);
+
+  /* insert key to source mesh */
+  Key *key = BKE_key_add(bmain, (ID *)mesh);
+  key->type = KEY_RELATIVE;
+
+  mesh->key = key;
+
+  /* insert basis key */
+  KeyBlock *kb = BKE_keyblock_add(key, "Basis");
+  BKE_keyblock_convert_from_mesh(mesh, key, kb);
+
+  pxr::UsdStageRefPtr stage = prim.GetStage();
+
+  if (!stage) {
+    return;
+  }
+
+  /* Keep track of the shapkeys we're adding, for
+   * validation when creating curves later. */
+  std::set<pxr::TfToken> shapekey_names;
+
+  for (int i = 0; i < targets.size(); ++i) {
+
+    const pxr::SdfPath &path = targets[i];
+
+    pxr::UsdSkelBlendShape blendshape(stage->GetPrimAtPath(path));
+
+    if (!blendshape) {
+      continue;
+    }
+
+    if (!blendshape.GetOffsetsAttr().HasAuthoredValue()) {
+      continue;
+    }
+
+    pxr::VtVec3fArray offsets;
+    if (!blendshape.GetOffsetsAttr().Get(&offsets)) {
+      std::cout << "Couldn't get offsets for blendshape " << path << std::endl;
+      continue;
+    }
+
+    shapekey_names.insert(blendshapes[i]);
+
+    kb = BKE_keyblock_add(key, blendshapes[i].GetString().c_str());
+    BKE_keyblock_convert_from_mesh(mesh, key, kb);
+
+    pxr::VtArray<int> point_indices;
+    if (blendshape.GetPointIndicesAttr().HasAuthoredValue()) {
+      blendshape.GetPointIndicesAttr().Get(&point_indices);
+    }
+
+    float *fp = static_cast<float *>(kb->data);
+
+    if (point_indices.empty()) {
+      for (int a = 0; a < kb->totelem; ++a, fp += 3) {
+        add_v3_v3(fp, offsets[a].data());
+      }
+    }
+    else {
+      int a = 0;
+      for (int i : point_indices) {
+        if (i < 0 || i > kb->totelem) {
+          std::cout << "out of bounds point index " << i << std::endl;
+ 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list