[Bf-blender-cvs] [b665ae266d9] universal-scene-description: USD export armatures with shapekeys WIP.

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


Commit: b665ae266d9332cec36cf35728a179719080ff9b
Author: Michael Kowalski
Date:   Sun Aug 7 14:07:07 2022 -0400
Branches: universal-scene-description
https://developer.blender.org/rBb665ae266d9332cec36cf35728a179719080ff9b

USD export armatures with shapekeys WIP.

Extended USDSkinnedMeshWriter to support exporting
blendshapes.

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

M	source/blender/io/usd/intern/usd_hierarchy_iterator.cc
M	source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
M	source/blender/io/usd/intern/usd_writer_blendshape_mesh.h
M	source/blender/io/usd/intern/usd_writer_mesh.cc
M	source/blender/io/usd/intern/usd_writer_mesh.h
M	source/blender/io/usd/intern/usd_writer_skinned_mesh.cc
M	source/blender/io/usd/intern/usd_writer_skinned_mesh.h

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

diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
index 5dcd42ace2b..de1b22de148 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
@@ -136,7 +136,7 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const Hierarch
           data_writer = new USDSkinnedMeshWriter(usd_export_context);
         }
         else if (usd_export_context.export_params.export_blendshapes &&
-            is_blendshape_mesh(context->object)) {
+                 is_blendshape_mesh(context->object)) {
           data_writer = new USDBlendShapeMeshWriter(usd_export_context);
         }
         else {
diff --git a/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc b/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
index d4dd84c44be..6f6a78f9974 100644
--- a/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_blendshape_mesh.cc
@@ -97,7 +97,6 @@ static void print_blendshape_info(Object *obj)
   // 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);
@@ -110,31 +109,34 @@ bool is_blendshape_mesh(Object *obj)
   return key && key->totkey > 0 && key->type == KEY_RELATIVE;
 }
 
-USDBlendShapeMeshWriter::USDBlendShapeMeshWriter(const USDExporterContext &ctx) : USDMeshWriter(ctx)
+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;
-    }
+    USDGenericMeshWriter::do_write(context);
   }
 
+  write_blendshape(context);
+}
+
+bool USDBlendShapeMeshWriter::is_supported(const HierarchyContext *context) const
+{
+  return is_blendshape_mesh(context->object) && USDGenericMeshWriter::is_supported(context);
+}
+
+bool USDBlendShapeMeshWriter::check_is_animated(const HierarchyContext &context) const
+{
+  const Key *key = get_shape_key(context.object);
+
+  return key && key->totkey > 0 && key->adt != nullptr;
+}
+
+void USDBlendShapeMeshWriter::write_blendshape(HierarchyContext &context) const
+{
   /* A blendshape writer might be created even if
    * there are no blendshapes, so check that blendshapes
    * exist before continuting. */
@@ -142,17 +144,6 @@ void USDBlendShapeMeshWriter::do_write(HierarchyContext &context)
     return;
   }
 
-  pxr::UsdStageRefPtr stage = usd_export_context_.stage;
-  pxr::UsdTimeCode timecode = get_export_time_code();
-
-  pxr::UsdPrim mesh_prim = stage->GetPrimAtPath(usd_export_context_.usd_path);
-
-  if (!mesh_prim.IsValid()) {
-    printf("WARNING: couldn't get valid mesh prim for blendshape mesh %s\n",
-           this->usd_export_context_.usd_path.GetString().c_str());
-    return;
-  }
-
   pxr::UsdSkelSkeleton skel = get_skeleton(context);
 
   if (!skel) {
@@ -163,7 +154,22 @@ void USDBlendShapeMeshWriter::do_write(HierarchyContext &context)
 
   const Key *key = get_shape_key(context.object);
 
+  if (!key) {
+    printf("WARNING: couldn't get shape key for blendshape mesh prim %s\n",
+           this->usd_export_context_.usd_path.GetString().c_str());
+    return;
+  }
+
   if (!this->frame_has_been_written_) {
+    pxr::UsdPrim mesh_prim = usd_export_context_.stage->GetPrimAtPath(
+        usd_export_context_.usd_path);
+
+    if (!mesh_prim.IsValid()) {
+      printf("WARNING: couldn't get valid mesh prim for blendshape mesh %s\n",
+             this->usd_export_context_.usd_path.GetString().c_str());
+      return;
+    }
+
     create_blend_shapes(key, mesh_prim, skel);
   }
 
@@ -172,18 +178,6 @@ void USDBlendShapeMeshWriter::do_write(HierarchyContext &context)
   }
 }
 
-bool USDBlendShapeMeshWriter::is_supported(const HierarchyContext *context) const
-{
-  return is_blendshape_mesh(context->object) && USDGenericMeshWriter::is_supported(context);
-}
-
-bool USDBlendShapeMeshWriter::check_is_animated(const HierarchyContext & context) const
-{
-  const Key *key = get_shape_key(context.object);
-
-  return key && key->totkey > 0 && key->adt != nullptr;
-}
-
 void USDBlendShapeMeshWriter::create_blend_shapes(const Key *key,
                                                   const pxr::UsdPrim &mesh_prim,
                                                   const pxr::UsdSkelSkeleton &skel) const
@@ -230,7 +224,8 @@ void USDBlendShapeMeshWriter::create_blend_shapes(const Key *key,
     pxr::SdfPath path = usd_export_context_.usd_path.AppendChild(name);
     blendshape_paths.push_back(path);
 
-    pxr::UsdSkelBlendShape blendshape = usd_export_context_.usd_define_or_over<pxr::UsdSkelBlendShape>(path);
+    pxr::UsdSkelBlendShape blendshape =
+        usd_export_context_.usd_define_or_over<pxr::UsdSkelBlendShape>(path);
 
     pxr::UsdAttribute offsets_attr = blendshape.CreateOffsetsAttr();
 
@@ -262,23 +257,19 @@ void USDBlendShapeMeshWriter::create_blend_shapes(const Key *key,
   blendshape_attr.Set(blendshape_names);
   skel_api.CreateBlendShapeTargetsRel().SetTargets(blendshape_paths);
 
-  /* Some DCCs seem to require joint names, indices and weights to
-   * bind the skeleton. */
-  pxr::VtTokenArray joints({usdtokens::joint1});
-  pxr::VtArray<int> joint_indices(basis_totelem, 0);
-  pxr::VtArray<float> joint_weights(basis_totelem, 1.0f);
-
-  skel_api.CreateJointsAttr().Set(joints);
-  skel_api.CreateJointIndicesPrimvar(false, 1).GetAttr().Set(joint_indices);
-  skel_api.CreateJointWeightsPrimvar(false, 1).GetAttr().Set(joint_weights);
+  /* Some DCCs seem to require joint indices and weights to
+   * bind the skeleton for blendshapes, so we we create these
+   * primvars, if needed. */
 
-  /* Initialize the skeleton. */
-  pxr::VtMatrix4dArray bind_transforms(1, pxr::GfMatrix4d(1.0));
-  pxr::VtMatrix4dArray rest_transforms(1, pxr::GfMatrix4d(1.0));
-  skel.CreateBindTransformsAttr().Set(bind_transforms);
-  skel.GetRestTransformsAttr().Set(rest_transforms);
+  if (!skel_api.GetJointIndicesAttr().HasAuthoredValue()) {
+    pxr::VtArray<int> joint_indices(basis_totelem, 0);
+    skel_api.CreateJointIndicesPrimvar(false, 1).GetAttr().Set(joint_indices);
+  }
 
-  skel.CreateJointsAttr().Set(joints);
+  if (!skel_api.GetJointWeightsAttr().HasAuthoredValue()) {
+    pxr::VtArray<float> joint_weights(basis_totelem, 1.0f);
+    skel_api.CreateJointWeightsPrimvar(false, 1).GetAttr().Set(joint_weights);
+  }
 
   /* Create the skeleton animation. */
   pxr::SdfPath anim_path = skel.GetPath().AppendChild(usdtokens::Anim);
@@ -286,12 +277,6 @@ void USDBlendShapeMeshWriter::create_blend_shapes(const Key *key,
       anim_path);
 
   if (anim) {
-    /* Specify the animation source on the skeleton. */
-    skel_api = pxr::UsdSkelBindingAPI::Apply(skel.GetPrim());
-    skel_api.CreateAnimationSourceRel().AddTarget(pxr::SdfPath(usdtokens::Anim));
-
-    anim.CreateJointsAttr().Set(joints);
-
     /* Set the blendshape names on the animation. */
     pxr::UsdAttribute blendshape_attr = anim.CreateBlendShapesAttr();
     blendshape_attr.Set(blendshape_names);
@@ -300,7 +285,6 @@ void USDBlendShapeMeshWriter::create_blend_shapes(const Key *key,
     pxr::UsdAttribute weights_attr = anim.CreateBlendShapeWeightsAttr();
     weights_attr.Set(weights);
   }
-
 }
 
 void USDBlendShapeMeshWriter::add_weights_sample(const Key *key,
@@ -324,7 +308,25 @@ pxr::UsdSkelSkeleton USDBlendShapeMeshWriter::get_skeleton(const HierarchyContex
   pxr::SdfPath skel_path = usd_export_context_.usd_path.GetParentPath().AppendChild(
       usdtokens::Skel);
 
-  return usd_export_context_.usd_define_or_over<pxr::UsdSkelSkeleton>(skel_path);
+  pxr::UsdSkelSkeleton skel = usd_export_context_.usd_define_or_over<pxr::UsdSkelSkeleton>(
+      skel_path);
+
+  /* Initialize the skeleton. */
+  pxr::VtMatrix4dArray bind_transforms(1, pxr::GfMatrix4d(1.0));
+  pxr::VtMatrix4dArray rest_transforms(1, pxr::GfMatrix4d(1.0));
+  skel.CreateBindTransformsAttr().Set(bind_transforms);
+  skel.GetRestTransformsAttr().Set(rest_transforms);
+
+  /* Some DCCs seem to require joint names to bind the
+   * skeleton to blendshapes. */
+  pxr::VtTokenArray joints({usdtokens::joint1});
+  skel.CreateJointsAttr().Set(joints);
+
+  /* Specify the animation source on the skeleton. */
+  pxr::UsdSkelBindingAPI skel_api(skel.GetPrim());
+  skel_api.CreateAnimationSourceRel().AddTarget(pxr::SdfPath(usdtokens::Anim));
+
+  return skel;
 }
 
 Mesh *USDBlendShapeMeshWriter::get_export_mesh(Object *object_eval, bool &r_needsfree)
@@ -352,8 +354,8 @@ Mesh *USDBlendShapeMeshWriter::get_export_mesh(Object *object_eval, bool &r_need
     return nullptr;
   }
 
-  Mesh *temp_mesh = reinterpret_cast<Mesh *>(BKE_id_copy_ex(
-      nullptr, &src_mesh->id, nullptr, LIB_ID_COPY_LOCALIZE));
+  Mesh *temp_mesh = reinterpret_cast<Mesh *>(
+      BKE_id_copy_ex(nullptr, &src_mesh->id, nullptr, LIB_ID_COPY_LOCALIZE));
 
   BKE_keyblock_convert_to_mesh(basis, temp_mesh->mvert, temp_mesh->totvert);
 
@@ -362,6 +364,19 @@ Mesh *USDBlendShapeMeshWriter::get_export_mesh(Object *object_eval, bool &r_need
   return temp_mesh;
 }
 
+/* Blend shape meshes are never animated, but the blendshape writer itself
+ * might be animating as it must add time samples to skeletal animations.
+ * This function ensures that the mesh data is written as non-timesampled.
+ * This is currently required to work around a bug in Create which causes
+ * a crash if the blendhshape mesh is timesa

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list