[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