diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index 65aaef6a8ce..547d59e36a6 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -105,6 +105,9 @@ if(WITH_ALEMBIC) endif() if(WITH_USD) + list(APPEND INC_SYS + ${USD_INCLUDE_DIRS} + ) list(APPEND LIB bf_io_usd ) diff --git a/source/blender/editors/io/io_usd.cc b/source/blender/editors/io/io_usd.cc index 2ecd1ca6838..b59a90bb31f 100644 --- a/source/blender/editors/io/io_usd.cc +++ b/source/blender/editors/io/io_usd.cc @@ -41,6 +41,8 @@ # include "io_utils.hh" # include "usd.hh" +# include + # include # include @@ -259,6 +261,12 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op) const int usdz_downscale_custom_size = RNA_int_get(op->ptr, "usdz_downscale_custom_size"); +# if PXR_VERSION >= 2403 + const bool allow_unicode = RNA_boolean_get(op->ptr, "allow_unicode"); +# else + const bool allow_unicode = false; +# endif + char root_prim_path[FILE_MAX]; RNA_string_get(op->ptr, "root_prim_path", root_prim_path); process_prim_path(root_prim_path); @@ -299,6 +307,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op) export_volumes, usdz_downscale_size, usdz_downscale_custom_size, + allow_unicode, }; STRNCPY(params.root_prim_path, root_prim_path); @@ -337,6 +346,9 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op) row = uiLayoutRow(col, true); uiItemR(row, ptr, "author_blender_name", UI_ITEM_NONE, nullptr, ICON_NONE); uiLayoutSetActive(row, RNA_boolean_get(op->ptr, "export_custom_properties")); +# if PXR_VERSION >= 2403 + uiItemR(col, ptr, "allow_unicode", UI_ITEM_NONE, nullptr, ICON_NONE); +# endif uiItemR(col, ptr, "convert_world_material", UI_ITEM_NONE, nullptr, ICON_NONE); @@ -645,6 +657,16 @@ void WM_OT_usd_export(wmOperatorType *ot) "Currently works for simple materials, consisting of an environment texture " "connected to a background shader, with an optional vector multiply of the texture color"); +# if PXR_VERSION >= 2403 + RNA_def_boolean( + ot->srna, + "allow_unicode", + false, + "Allow Unicode", + "Preserve UTF-8 encoded characters when writing USD prim and property names " + "(requires software utilizing USD 24.03 or greater when opening the resulting files)"); +# endif + RNA_def_boolean(ot->srna, "export_meshes", true, "Meshes", "Export all meshes"); RNA_def_boolean(ot->srna, "export_lights", true, "Lights", "Export all lights"); diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index c85dcd83ab1..8d84d2e6009 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -97,6 +97,7 @@ set(SRC intern/usd_hook.cc intern/usd_light_convert.cc intern/usd_mesh_utils.cc + intern/usd_utils.cc intern/usd_writer_abstract.cc intern/usd_writer_armature.cc @@ -143,6 +144,7 @@ set(SRC intern/usd_hook.hh intern/usd_light_convert.hh intern/usd_mesh_utils.hh + intern/usd_utils.hh intern/usd_writer_abstract.hh intern/usd_writer_armature.hh diff --git a/source/blender/io/usd/intern/usd_armature_utils.cc b/source/blender/io/usd/intern/usd_armature_utils.cc index 1476735ab03..45c12bac0bc 100644 --- a/source/blender/io/usd/intern/usd_armature_utils.cc +++ b/source/blender/io/usd/intern/usd_armature_utils.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd_armature_utils.hh" +#include "usd_utils.hh" #include "BKE_armature.hh" #include "BKE_modifier.hh" @@ -95,22 +96,23 @@ void get_armature_bone_names(const Object *ob_arm, visit_bones(ob_arm, visitor); } -pxr::TfToken build_usd_joint_path(const Bone *bone) +pxr::TfToken build_usd_joint_path(const Bone *bone, bool allow_unicode) { - std::string path(pxr::TfMakeValidIdentifier(bone->name)); + std::string path(bone->name); const Bone *parent = bone->parent; while (parent) { - path = pxr::TfMakeValidIdentifier(parent->name) + std::string("/") + path; + path = parent->name + std::string("/") + path; parent = parent->parent; } - return pxr::TfToken(path); + return pxr::TfToken(make_safe_name(path, allow_unicode)); } void create_pose_joints(pxr::UsdSkelAnimation &skel_anim, const Object &obj, - const Map *deform_map) + const Map *deform_map, + bool allow_unicode) { BLI_assert(obj.pose); @@ -126,7 +128,7 @@ void create_pose_joints(pxr::UsdSkelAnimation &skel_anim, continue; } - joints.push_back(build_usd_joint_path(pchan->bone)); + joints.push_back(build_usd_joint_path(pchan->bone, allow_unicode)); } } diff --git a/source/blender/io/usd/intern/usd_armature_utils.hh b/source/blender/io/usd/intern/usd_armature_utils.hh index c2c74982ba8..694602b9064 100644 --- a/source/blender/io/usd/intern/usd_armature_utils.hh +++ b/source/blender/io/usd/intern/usd_armature_utils.hh @@ -46,9 +46,10 @@ void get_armature_bone_names(const Object *ob_arm, bool use_deform, Vector *deform_map); + const Map *deform_map, + bool allow_unicode); /** * Return the modifier of the given type enabled for the given dependency graph's diff --git a/source/blender/io/usd/intern/usd_blend_shape_utils.cc b/source/blender/io/usd/intern/usd_blend_shape_utils.cc index bb7be6c07ac..ca92e055713 100644 --- a/source/blender/io/usd/intern/usd_blend_shape_utils.cc +++ b/source/blender/io/usd/intern/usd_blend_shape_utils.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd_blend_shape_utils.hh" +#include "usd_utils.hh" #include #include @@ -190,7 +191,8 @@ bool is_mesh_with_shape_keys(const Object *obj) void create_blend_shapes(pxr::UsdStageRefPtr stage, const Object *obj, - const pxr::UsdPrim &mesh_prim) + const pxr::UsdPrim &mesh_prim, + bool allow_unicode) { const Key *key = get_mesh_shape_key(obj); @@ -229,7 +231,7 @@ void create_blend_shapes(pxr::UsdStageRefPtr stage, continue; } - pxr::TfToken name(pxr::TfMakeValidIdentifier(kb->name)); + pxr::TfToken name(make_safe_name(kb->name, allow_unicode)); blendshape_names.push_back(name); pxr::SdfPath path = mesh_prim.GetPath().AppendChild(name); diff --git a/source/blender/io/usd/intern/usd_blend_shape_utils.hh b/source/blender/io/usd/intern/usd_blend_shape_utils.hh index 935df6ccf84..c2557f9ed1b 100644 --- a/source/blender/io/usd/intern/usd_blend_shape_utils.hh +++ b/source/blender/io/usd/intern/usd_blend_shape_utils.hh @@ -44,10 +44,12 @@ bool is_mesh_with_shape_keys(const Object *obj); * \param stage: The stage * \param obj: The mesh object whose shape keys will be converted to blend shapes * \param mesh_prim: The USD mesh that will be assigned the blend shape targets + * \param allow_unicode: Whether to allow unicode encoded characters in the blend shape name */ void create_blend_shapes(pxr::UsdStageRefPtr stage, const Object *obj, - const pxr::UsdPrim &mesh_prim); + const pxr::UsdPrim &mesh_prim, + bool allow_unicode); /** * Return the current weight values of the given key. diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc index f0e29de64b2..4281d29b36a 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc @@ -8,6 +8,7 @@ #include "usd_hierarchy_iterator.hh" #include "usd_skel_convert.hh" #include "usd_skel_root_utils.hh" +#include "usd_utils.hh" #include "usd_writer_abstract.hh" #include "usd_writer_armature.hh" #include "usd_writer_camera.hh" @@ -21,8 +22,6 @@ #include -#include - #include "BKE_main.hh" #include "BLI_assert.h" @@ -78,7 +77,7 @@ void USDHierarchyIterator::release_writer(AbstractHierarchyWriter *writer) std::string USDHierarchyIterator::make_valid_name(const std::string &name) const { - return pxr::TfMakeValidIdentifier(name); + return make_safe_name(name, params_.allow_unicode); } void USDHierarchyIterator::process_usd_skel() const diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index 3c6a3e23d91..266db3b28cb 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -3,9 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd_reader_material.hh" -#include "usd_reader_utils.hh" - #include "usd_asset_utils.hh" +#include "usd_reader_utils.hh" +#include "usd_utils.hh" #include "BKE_appdir.hh" #include "BKE_image.h" @@ -1359,7 +1359,7 @@ void build_material_map(const Main *bmain, blender::Map BLI_assert_msg(r_mat_map, "..."); LISTBASE_FOREACH (Material *, material, &bmain->materials) { - std::string usd_name = pxr::TfMakeValidIdentifier(material->id.name + 2); + std::string usd_name = make_safe_name(material->id.name + 2, true); r_mat_map->lookup_or_add_default(usd_name) = material; } } diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index c07c971e5da..f3bc638fc99 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -11,6 +11,7 @@ #include "usd_mesh_utils.hh" #include "usd_reader_material.hh" #include "usd_skel_convert.hh" +#include "usd_utils.hh" #include "BKE_attribute.hh" #include "BKE_customdata.hh" @@ -84,6 +85,7 @@ static void assign_materials(Main *bmain, blender::Map &mat_name_to_mat, blender::Map &usd_path_to_mat_name) { + using namespace blender::io::usd; if (!(stage && bmain && ob)) { return; } @@ -92,7 +94,7 @@ static void assign_materials(Main *bmain, return; } - blender::io::usd::USDMaterialReader mat_reader(params, bmain); + USDMaterialReader mat_reader(params, bmain); for (const auto item : mat_index_map.items()) { Material *assigned_mat = blender::io::usd::find_existing_material( @@ -120,10 +122,10 @@ static void assign_materials(Main *bmain, continue; } - const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2); + const std::string mat_name = make_safe_name(assigned_mat->id.name + 2, true); mat_name_to_mat.lookup_or_add_default(mat_name) = assigned_mat; - if (params.mtl_name_collision_mode == blender::io::usd::USD_MTL_NAME_COLLISION_MAKE_UNIQUE) { + if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) { /* Record the name of the Blender material we created for the USD material * with the given path. */ usd_path_to_mat_name.lookup_or_add_default(item.key.GetAsString()) = mat_name; diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc index 1583ced7167..be3e52bceee 100644 --- a/source/blender/io/usd/intern/usd_reader_stage.cc +++ b/source/blender/io/usd/intern/usd_reader_stage.cc @@ -17,6 +17,7 @@ #include "usd_reader_skeleton.hh" #include "usd_reader_volume.hh" #include "usd_reader_xform.hh" +#include "usd_utils.hh" #include #include @@ -566,7 +567,7 @@ void USDStageReader::import_all_materials(Main *bmain) Material *new_mtl = mtl_reader.add_material(usd_mtl); BLI_assert_msg(new_mtl, "Failed to create material"); - const std::string mtl_name = pxr::TfMakeValidIdentifier(new_mtl->id.name + 2); + const std::string mtl_name = make_safe_name(new_mtl->id.name + 2, true); settings_.mat_name_to_mat.lookup_or_add_default(mtl_name) = new_mtl; if (params_.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) { diff --git a/source/blender/io/usd/intern/usd_utils.cc b/source/blender/io/usd/intern/usd_utils.cc new file mode 100644 index 00000000000..dba289cbd72 --- /dev/null +++ b/source/blender/io/usd/intern/usd_utils.cc @@ -0,0 +1,52 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "usd_utils.hh" + +#include "BLI_string_utf8.h" + +#include +#if PXR_VERSION >= 2403 +# include +#endif + +namespace blender::io::usd { + +std::string make_safe_name(const std::string &name, [[maybe_unused]] bool allow_unicode) +{ +#if PXR_VERSION >= 2403 + if (!allow_unicode) { + return pxr::TfMakeValidIdentifier(name); + } + + if (name.empty()) { + return "_"; + } + + std::string buf; + buf.resize(name.size()); // We won't be exceeding the size of the incoming string + + bool first = true; + size_t offset = 0; + for (auto cp : pxr::TfUtf8CodePointView{name}) { + constexpr pxr::TfUtf8CodePoint cp_underscore = pxr::TfUtf8CodePointFromAscii('_'); + const bool cp_allowed = first ? (cp == cp_underscore || pxr::TfIsUtf8CodePointXidStart(cp)) : + pxr::TfIsUtf8CodePointXidContinue(cp); + if (!cp_allowed) { + offset += BLI_str_utf8_from_unicode(uint32_t('_'), buf.data() + offset, buf.size() - offset); + } + else { + offset += BLI_str_utf8_from_unicode(cp.AsUInt32(), buf.data() + offset, buf.size() - offset); + } + + first = false; + } + + return buf; +#else + return pxr::TfMakeValidIdentifier(name); +#endif +} + +} // namespace blender::io::usd diff --git a/source/blender/io/usd/intern/usd_utils.hh b/source/blender/io/usd/intern/usd_utils.hh new file mode 100644 index 00000000000..23285e112f3 --- /dev/null +++ b/source/blender/io/usd/intern/usd_utils.hh @@ -0,0 +1,19 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ +#pragma once + +#include + +namespace blender::io::usd { + +/** + * Return a valid USD identifier based on the passed in string. + * + * \param name: Incoming name to sanitize + * \param allow_unicode: Whether to allow unicode encoded characters in the USD identifier + * \return A valid USD identifier + */ +std::string make_safe_name(const std::string &name, bool allow_unicode); + +} // namespace blender::io::usd diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc index 79497a75732..8581c202b58 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.cc +++ b/source/blender/io/usd/intern/usd_writer_abstract.cc @@ -2,9 +2,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd_writer_abstract.hh" +#include "usd_utils.hh" #include "usd_writer_material.hh" -#include #include #include @@ -213,7 +213,8 @@ pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(const HierarchyCont pxr::UsdStageRefPtr stage = usd_export_context_.stage; /* Construct the material. */ - pxr::TfToken material_name(pxr::TfMakeValidIdentifier(material->id.name + 2)); + pxr::TfToken material_name( + make_safe_name(material->id.name + 2, usd_export_context_.export_params.allow_unicode)); pxr::SdfPath usd_path = pxr::UsdGeomScope::Define(stage, get_material_library_path()) .GetPath() .AppendChild(material_name); @@ -325,7 +326,8 @@ void USDAbstractWriter::write_user_properties(const pxr::UsdPrim &prim, continue; } - std::string prop_name = pxr::TfMakeValidIdentifier(prop->name); + std::string prop_name = make_safe_name(prop->name, + usd_export_context_.export_params.allow_unicode); std::string full_prop_name = "userProperties:" + prop_name; pxr::TfToken prop_token = pxr::TfToken(full_prop_name); diff --git a/source/blender/io/usd/intern/usd_writer_armature.cc b/source/blender/io/usd/intern/usd_writer_armature.cc index 34ec8b45436..091ef9ed58b 100644 --- a/source/blender/io/usd/intern/usd_writer_armature.cc +++ b/source/blender/io/usd/intern/usd_writer_armature.cc @@ -48,7 +48,8 @@ static pxr::GfMatrix4d parent_relative_pose_mat(const bPoseChannel *pchan) static void initialize(const Object *obj, pxr::UsdSkelSkeleton &skel, pxr::UsdSkelAnimation &skel_anim, - const blender::Map *deform_bones) + const blender::Map *deform_bones, + bool allow_unicode) { using namespace blender::io::usd; @@ -68,7 +69,7 @@ static void initialize(const Object *obj, return; } - joints.push_back(build_usd_joint_path(bone)); + joints.push_back(build_usd_joint_path(bone, allow_unicode)); const pxr::GfMatrix4f arm_mat(bone->arm_mat); bind_xforms.push_back(pxr::GfMatrix4d(arm_mat)); @@ -97,7 +98,7 @@ static void initialize(const Object *obj, if (skel_anim) { usd_skel_api.CreateAnimationSourceRel().SetTargets( pxr::SdfPathVector({pxr::SdfPath(usdtokens::Anim)})); - create_pose_joints(skel_anim, *obj, deform_bones); + create_pose_joints(skel_anim, *obj, deform_bones, allow_unicode); } } @@ -166,13 +167,14 @@ void USDArmatureWriter::do_write(HierarchyContext &context) } } + const bool allow_unicode = usd_export_context_.export_params.allow_unicode; Map *deform_map = usd_export_context_.export_params.only_deform_bones ? &deform_map_ : nullptr; if (!this->frame_has_been_written_) { init_deform_bones_map(context.object, deform_map); - initialize(context.object, skel, skel_anim, deform_map); + initialize(context.object, skel, skel_anim, deform_map, allow_unicode); } if (usd_export_context_.export_params.export_animation) { diff --git a/source/blender/io/usd/intern/usd_writer_curves.cc b/source/blender/io/usd/intern/usd_writer_curves.cc index f9d583ea13f..0214eb92d96 100644 --- a/source/blender/io/usd/intern/usd_writer_curves.cc +++ b/source/blender/io/usd/intern/usd_writer_curves.cc @@ -16,6 +16,7 @@ #include "usd_attribute_utils.hh" #include "usd_hierarchy_iterator.hh" +#include "usd_utils.hh" #include "usd_writer_curves.hh" #include "BLI_array_utils.hh" @@ -405,7 +406,8 @@ void USDCurvesWriter::write_generic_data(const bke::CurvesGeometry &curves, } const pxr::UsdTimeCode timecode = get_export_time_code(); - const pxr::TfToken pv_name(pxr::TfMakeValidIdentifier(attribute_id.name())); + const pxr::TfToken pv_name( + make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode)); const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves); pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp); @@ -425,7 +427,8 @@ void USDCurvesWriter::write_uv_data(const bke::CurvesGeometry &curves, } const pxr::UsdTimeCode timecode = get_export_time_code(); - const pxr::TfToken pv_name(pxr::TfMakeValidIdentifier(attribute_id.name())); + const pxr::TfToken pv_name( + make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode)); const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves); pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar( diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 0c0c78d9432..dbd14cdda4b 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -3,9 +3,10 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd_writer_material.hh" - #include "usd_exporter_context.hh" #include "usd_hook.hh" +#include "usd_utils.hh" +#include "usd_writer_abstract.hh" #include "BKE_image.h" #include "BKE_image_format.h" @@ -472,7 +473,8 @@ static void create_uvmap_shader(const USDExporterContext &usd_export_context, if (uv_node && uv_node->storage) { NodeShaderUVMap *shader_uv_map = static_cast(uv_node->storage); /* We need to make valid here because actual uv primvar has been. */ - uv_name = pxr::TfMakeValidIdentifier(shader_uv_map->uv_map); + uv_name = make_safe_name(shader_uv_map->uv_map, + usd_export_context.export_params.allow_unicode); } uv_shader.CreateInput(usdtokens::varname, pxr::SdfValueTypeNames->String).Set(uv_name); @@ -778,7 +780,7 @@ static pxr::UsdShadeShader create_usd_preview_shader(const USDExporterContext &u const int type) { pxr::SdfPath shader_path = material.GetPath().AppendChild( - pxr::TfToken(pxr::TfMakeValidIdentifier(name))); + pxr::TfToken(make_safe_name(name, usd_export_context.export_params.allow_unicode))); pxr::UsdShadeShader shader = pxr::UsdShadeShader::Define(usd_export_context.stage, shader_path); switch (type) { diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index b9e9257c65b..58e63956a5a 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -7,6 +7,7 @@ #include "usd_attribute_utils.hh" #include "usd_blend_shape_utils.hh" #include "usd_skel_convert.hh" +#include "usd_utils.hh" #include #include @@ -261,7 +262,8 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh, } const pxr::UsdTimeCode timecode = get_export_time_code(); - const pxr::TfToken pv_name(pxr::TfMakeValidIdentifier(attribute_id.name())); + const pxr::TfToken pv_name( + make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode)); const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh); pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp); @@ -282,7 +284,8 @@ void USDGenericMeshWriter::write_uv_data(const Mesh *mesh, } const pxr::UsdTimeCode timecode = get_export_time_code(); - const pxr::TfToken pv_name(pxr::TfMakeValidIdentifier(attribute_id.name())); + const pxr::TfToken pv_name( + make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode)); const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh); pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar( @@ -303,7 +306,8 @@ void USDGenericMeshWriter::write_color_data(const Mesh *mesh, } const pxr::UsdTimeCode timecode = get_export_time_code(); - const pxr::TfToken pv_name(pxr::TfMakeValidIdentifier(attribute_id.name())); + const pxr::TfToken pv_name( + make_safe_name(attribute_id.name(), usd_export_context_.export_params.allow_unicode)); const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh); /* Varying type depends on original domain. */ @@ -876,7 +880,10 @@ void USDMeshWriter::init_blend_shapes(const HierarchyContext &context) return; } - create_blend_shapes(this->usd_export_context_.stage, context.object, mesh_prim); + create_blend_shapes(this->usd_export_context_.stage, + context.object, + mesh_prim, + usd_export_context_.export_params.allow_unicode); } void USDMeshWriter::do_write(HierarchyContext &context) diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc index 78168a549ac..2e1997eb463 100644 --- a/source/blender/io/usd/intern/usd_writer_volume.cc +++ b/source/blender/io/usd/intern/usd_writer_volume.cc @@ -4,6 +4,7 @@ #include "usd_writer_volume.hh" #include "usd_hierarchy_iterator.hh" +#include "usd_utils.hh" #include #include @@ -73,7 +74,8 @@ void USDVolumeWriter::do_write(HierarchyContext &context) for (const int i : IndexRange(num_grids)) { const bke::VolumeGridData *grid = BKE_volume_grid_get(volume, i); const std::string grid_name = bke::volume_grid::get_name(*grid); - const std::string grid_id = pxr::TfMakeValidIdentifier(grid_name); + const std::string grid_id = make_safe_name(grid_name, + usd_export_context_.export_params.allow_unicode); const pxr::SdfPath grid_path = volume_path.AppendPath(pxr::SdfPath(grid_id)); pxr::UsdVolOpenVDBAsset usd_grid = pxr::UsdVolOpenVDBAsset::Define(stage, grid_path); usd_grid.GetFieldNameAttr().Set(pxr::TfToken(grid_name), timecode); diff --git a/source/blender/io/usd/usd.hh b/source/blender/io/usd/usd.hh index bc468fd1e39..d6c9497dd9c 100644 --- a/source/blender/io/usd/usd.hh +++ b/source/blender/io/usd/usd.hh @@ -129,9 +129,11 @@ struct USDExportParams { bool export_cameras = true; bool export_curves = true; bool export_volumes = true; - eUSDZTextureDownscaleSize usdz_downscale_size = eUSDZTextureDownscaleSize::USD_TEXTURE_SIZE_KEEP; int usdz_downscale_custom_size = 128; + + bool allow_unicode = false; + char root_prim_path[1024] = ""; /* FILE_MAX */ char collection[MAX_IDPROP_NAME] = "";