Commit: cdef135f6f651c669f526a931a3cfd996d1e8cbd Author: Michael Kowalski Date: Thu Jan 26 18:08:45 2023 -0500 Branches: master https://developer.blender.org/rBcdef135f6f651c669f526a931a3cfd996d1e8cbd
USD import: Support importing USDZ. This addressed feature request T99811. Added the following features to fully support importing USDZ archives: - Added .usdz to the list of supported extensions. - Added new USD import options to copy textures from USDZ archives. The textures may be imported as packed data (the default) or to a directory on disk. - Extended the USD material import logic to handle package-relative texture assets paths by invoking the USD asset resolver to copy the textures from the USDZ archive to a directory on disk. When importing in Packed mode, the textures are first saved to Blender's temporary session directory prior to packing. The new USD import options are - Import Textures: Behavior when importing textures from a USDZ archive - Textures Directory: Path to the directory where imported textures will be copied - File Name Collision: Behavior when the name of an imported texture file conflicts with an existing file Import Textures menu options: - None: Don't import textures - Packed: Import textures as packed data (the default) - Copy: Copy files to Textures Directory File Name Collision menu options: - Use Existing: If a file with the same name already exists, use that instead of copying (the default) - Overwrite: Overwrite existing files Reviewed by: Bastien Differential Revision: https://developer.blender.org/D17074 =================================================================== M release/scripts/startup/bl_ui/space_topbar.py M source/blender/blenkernel/intern/cachefile.c M source/blender/editors/io/io_usd.c M source/blender/editors/space_file/filelist.cc M source/blender/io/usd/CMakeLists.txt A source/blender/io/usd/intern/usd_asset_utils.cc A source/blender/io/usd/intern/usd_asset_utils.h M source/blender/io/usd/intern/usd_reader_material.cc M source/blender/io/usd/usd.h =================================================================== diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 97f8a1bfad1..50bb1e42602 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -468,7 +468,7 @@ class TOPBAR_MT_file_import(Menu): self.layout.operator("wm.alembic_import", text="Alembic (.abc)") if bpy.app.build_options.usd: self.layout.operator( - "wm.usd_import", text="Universal Scene Description (.usd, .usdc, .usda)") + "wm.usd_import", text="Universal Scene Description (.usd*)") if bpy.app.build_options.io_gpencil: self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil") diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 5d19db323f8..5968a6b7296 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -366,7 +366,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file } #endif #ifdef WITH_USD - if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc")) { + if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) { cache_file->type = CACHEFILE_TYPE_USD; cache_file->handle = USD_create_handle(bmain, filepath, &cache_file->object_paths); BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index 99d4e84cfd4..e6426732584 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -72,6 +72,23 @@ const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_usd_tex_import_mode_items[] = { + {USD_TEX_IMPORT_NONE, "IMPORT_NONE", 0, "None", "Don't import textures"}, + {USD_TEX_IMPORT_PACK, "IMPORT_PACK", 0, "Packed", "Import textures as packed data"}, + {USD_TEX_IMPORT_COPY, "IMPORT_COPY", 0, "Copy", "Copy files to Textures Directory"}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_usd_tex_name_collision_mode_items[] = { + {USD_TEX_NAME_COLLISION_USE_EXISTING, + "USE_EXISTING", + 0, + "Use Existing", + "If a file with the same name already exists, use that instead of copying"}, + {USD_TEX_NAME_COLLISION_OVERWRITE, "OVERWRITE", 0, "Overwrite", "Overwrite existing files"}, + {0, NULL, 0, NULL, NULL}, +}; + /* Stored in the wmOperator's customdata field to indicate it should run as a background job. * This is set when the operator is invoked, and not set when it is only executed. */ enum { AS_BACKGROUND_JOB = 1 }; @@ -405,6 +422,14 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) const bool validate_meshes = false; const bool use_instancing = false; + const eUSDTexImportMode import_textures_mode = RNA_enum_get(op->ptr, "import_textures_mode"); + + char import_textures_dir[FILE_MAXDIR]; + RNA_string_get(op->ptr, "import_textures_dir", import_textures_dir); + + const eUSDTexNameCollisionMode tex_name_collision_mode = RNA_enum_get(op->ptr, + "tex_name_collision_mode"); + struct USDImportParams params = {.scale = scale, .is_sequence = is_sequence, .set_frame_range = set_frame_range, @@ -430,9 +455,12 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) .set_material_blend = set_material_blend, .light_intensity_scale = light_intensity_scale, .mtl_name_collision_mode = mtl_name_collision_mode, + .import_textures_mode = import_textures_mode, + .tex_name_collision_mode = tex_name_collision_mode, .import_all_materials = import_all_materials}; STRNCPY(params.prim_path_mask, prim_path_mask); + STRNCPY(params.import_textures_dir, import_textures_dir); const bool ok = USD_import(C, filename, ¶ms, as_background_job); @@ -490,6 +518,18 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op) uiItemR(row, ptr, "set_material_blend", 0, NULL, ICON_NONE); uiLayoutSetEnabled(row, RNA_boolean_get(ptr, "import_usd_preview")); uiItemR(col, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + col = uiLayoutColumn(box, true); + uiItemR(col, ptr, "import_textures_mode", 0, NULL, ICON_NONE); + bool copy_textures = RNA_enum_get(op->ptr, "import_textures_mode") == USD_TEX_IMPORT_COPY; + row = uiLayoutRow(col, true); + uiItemR(row, ptr, "import_textures_dir", 0, NULL, ICON_NONE); + uiLayoutSetEnabled(row, copy_textures); + row = uiLayoutRow(col, true); + uiItemR(row, ptr, "tex_name_collision_mode", 0, NULL, ICON_NONE); + uiLayoutSetEnabled(row, copy_textures); + uiLayoutSetEnabled(col, RNA_boolean_get(ptr, "import_materials")); } void WM_OT_usd_import(struct wmOperatorType *ot) @@ -622,6 +662,28 @@ void WM_OT_usd_import(struct wmOperatorType *ot) USD_MTL_NAME_COLLISION_MAKE_UNIQUE, "Material Name Collision", "Behavior when the name of an imported material conflicts with an existing material"); + + RNA_def_enum(ot->srna, + "import_textures_mode", + rna_enum_usd_tex_import_mode_items, + USD_TEX_IMPORT_PACK, + "Import Textures", + "Behavior when importing textures from a USDZ archive"); + + RNA_def_string(ot->srna, + "import_textures_dir", + "//textures/", + FILE_MAXDIR, + "Textures Directory", + "Path to the directory where imported textures will be copied "); + + RNA_def_enum( + ot->srna, + "tex_name_collision_mode", + rna_enum_usd_tex_name_collision_mode_items, + USD_TEX_NAME_COLLISION_USE_EXISTING, + "File Name Collision", + "Behavior when the name of an imported texture file conflicts with an existing file"); } #endif /* WITH_USD */ diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 57a4c5c052a..73de74ddaf6 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -2667,7 +2667,7 @@ int ED_path_extension_type(const char *path) if (BLI_path_extension_check(path, ".abc")) { return FILE_TYPE_ALEMBIC; } - if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", nullptr)) { + if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", ".usdz", nullptr)) { return FILE_TYPE_USD; } if (BLI_path_extension_check(path, ".vdb")) { diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 862bd41c087..b123eb251ab 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -60,6 +60,7 @@ set(INC_SYS ) set(SRC + intern/usd_asset_utils.cc intern/usd_capi_export.cc intern/usd_capi_import.cc intern/usd_common.cc @@ -88,6 +89,7 @@ set(SRC usd.h + intern/usd_asset_utils.h intern/usd_common.h intern/usd_exporter_context.h intern/usd_hierarchy_iterator.h diff --git a/source/blender/io/usd/intern/usd_asset_utils.cc b/source/blender/io/usd/intern/usd_asset_utils.cc new file mode 100644 index 00000000000..550d318cd94 --- /dev/null +++ b/source/blender/io/usd/intern/usd_asset_utils.cc @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 NVIDIA Corportation. All rights reserved. */ + +#include "usd_asset_utils.h" + +#include <pxr/usd/ar/asset.h> +#include <pxr/usd/ar/packageUtils.h> +#include <pxr/usd/ar/resolver.h> +#include <pxr/usd/ar/writableAsset.h> + +#include "BKE_main.h" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "WM_api.h" +#include "WM_types.h" + +static const char UDIM_PATTERN[] = "<UDIM>"; +static const char UDIM_PATTERN2[] = "%3CUDIM%3E"; + +/* Maximum range of UDIM tiles, per the + * UsdPreviewSurface specifications. See + * https://graphics.pixar.com/usd/release/spec_usdpreviewsurface.html#texture-reader + */ +static const int UDIM_START_TILE = 1001; +static const int UDIM_END_TILE = 1100; + +namespace blender::io::usd { + +/* The following is copied from _SplitUdimPattern() in + * USD library source file materialParamsUtils.cpp. + * Split a udim file path such as /someDir/myFile.<UDIM>.exr into a + * prefix (/someDir/myFile.) and suffix (.exr). */ +static std::pair<std::string, std::string> split_udim_pattern(const std::string &path) +{ + static const std::vector<std::string> patterns = {UDIM_PATTERN, UDIM_PATTERN2}; + + for (const std::string &pattern : patterns) { + const std::string::size_type pos = path.find(pattern); + if (pos != std::string::npos) { + return {path.substr(0, pos), path.substr(pos + pattern.size())}; + } + } + + return {std::string(), std::string()}; +} + +/* Return the asset file base name, with special handling of + * package relative paths. */ +static std::string get_asset_base_name(const char *src_path) +{ + char base_name[FILE_MAXFILE]; + + if (pxr::ArIsPackageRelativePath(src_path)) { + std::pair<std::string, std::string> split = pxr::ArSplitPackageRelativePathInner(src_path); + if (split.second.empty()) { + WM_reportf(RPT_WARNING, + "%s: Couldn't determine package-relative file name from path %s", + __func__, + src_path); + return src_path; + } + BLI_split_file_part(split.second.c_str(), base_name, sizeof(base_name)); + } + else { + BLI_split_file_part(src_path, base_name, sizeof(base_name)); + } + + return base_name; +} + +/* Copy an asset to a destination directory. */ +static std::string copy_asset_to_directory(const char *src_path, + const char *dest_dir_path, + @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs