[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