[Bf-blender-cvs] [91ba17da8b2] tmp-dynamic-usd: USD import textures option.

Michael Kowalski noreply at git.blender.org
Tue Nov 29 01:16:48 CET 2022


Commit: 91ba17da8b26cd7e9eb9ed77ea27a7327f7c4e96
Author: Michael Kowalski
Date:   Mon Nov 28 09:56:15 2022 -0500
Branches: tmp-dynamic-usd
https://developer.blender.org/rB91ba17da8b26cd7e9eb9ed77ea27a7327f7c4e96

USD import textures option.

Added USD import option to copy textures which are
not on the local file system (e.g., textures in USDZ
archives or those specified by custom URIs) to a
designated directory using the USD ArResolver.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/intern/usd_asset_utils.cc
M	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/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 313e2488ace..131e86af1df 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -1103,6 +1103,13 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
 
   const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
 
+  const bool import_textures = RNA_boolean_get(op->ptr, "import_textures");
+
+  char import_textures_dir[FILE_MAX];
+  RNA_string_get(op->ptr, "import_textures_dir", import_textures_dir);
+
+  const bool overwrite_textures = RNA_boolean_get(op->ptr, "overwrite_textures");
+
   /* TODO(makowalski): Add support for sequences. */
   const bool is_sequence = false;
   int offset = 0;
@@ -1147,9 +1154,12 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
                                    .create_background_shader = create_background_shader,
                                    .mtl_name_collision_mode = mtl_name_collision_mode,
                                    .attr_import_mode = attr_import_mode,
-                                   .import_shapes = import_shapes};
+                                   .import_shapes = import_shapes,
+                                   .import_textures = import_textures,
+                                   .overwrite_textures = overwrite_textures};
 
   STRNCPY(params.prim_path_mask, prim_path_mask);
+  STRNCPY(params.import_textures_dir, import_textures_dir);
 
   const bool ok = USD_import(C, filename, &params, as_background_job);
 
@@ -1221,6 +1231,16 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   row = uiLayoutRow(col, true);
   uiItemR(row, ptr, "set_material_blend", 0, NULL, ICON_NONE);
   uiLayoutSetEnabled(row, import_mtls);
+  col = uiLayoutColumn(box, true);
+  uiItemR(col, ptr, "import_textures", 0, NULL, ICON_NONE);
+  bool import_textures = RNA_boolean_get(ptr, "import_textures");
+  row = uiLayoutRow(col, true);
+  uiItemR(row, ptr, "import_textures_dir", 0, NULL, ICON_NONE);
+  uiLayoutSetEnabled(row, import_textures);
+  row = uiLayoutRow(col, true);
+  uiItemR(row, ptr, "overwrite_textures", 0, NULL, ICON_NONE);
+  uiLayoutSetEnabled(row, import_textures);
+  uiLayoutSetEnabled(col, import_mtls);
 }
 
 void WM_OT_usd_import(struct wmOperatorType *ot)
@@ -1407,6 +1427,27 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
                   false,
                   "Validate Meshes",
                   "Validate meshes for degenerate geometry on import");
+
+   RNA_def_boolean(ot->srna,
+                  "import_textures",
+                  false,
+                  "Import Textures",
+                  "Copy textures which not on the local file system "
+                  "(e.g., textures in USDZ archives or referenced by custom URIs) "
+                  "to the directory given by the Import Textures Directory option");
+
+  RNA_def_string(ot->srna,
+                  "import_textures_dir",
+                  "//textures/",
+                  FILE_MAX,
+                  "Textures Directory",
+                  "Path to the directory where imported textures will be copied");
+
+  RNA_def_boolean(ot->srna,
+                  "overwrite_textures",
+                  false,
+                  "Overwrite Textures",
+                  "Allow overwriting existing files when copying imported textures");
 }
 
 #endif /* WITH_USD */
diff --git a/source/blender/io/usd/intern/usd_asset_utils.cc b/source/blender/io/usd/intern/usd_asset_utils.cc
index c2aa0d142ab..ec97d0d2b2d 100644
--- a/source/blender/io/usd/intern/usd_asset_utils.cc
+++ b/source/blender/io/usd/intern/usd_asset_utils.cc
@@ -4,9 +4,13 @@
 #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"
 
@@ -15,8 +19,128 @@
 
 #include <iostream>
 
+static const char UDIM_PATTERN[] = "<UDIM>";
+static const char UDIM_PATTERN2[] = "%3CUDIM%3E";
+static const int UDIM_START_TILE = 1001;
+static const int UDIM_END_TILE = 1100;
+
 namespace blender::io::usd {
 
+static std::string get_asset_file_name(const char *src_path)
+{
+  char file_name[FILE_MAX];
+
+  if (pxr::ArIsPackageRelativePath(src_path)) {
+    std::pair<std::string, std::string> split = pxr::ArSplitPackageRelativePathInner(src_path);
+    if (split.second.empty()) {
+      WM_reportf(
+          RPT_WARNING,
+          "usd_import_texture(): Couldn't determine package-relative file name from path %s.",
+          src_path);
+      return src_path;
+    }
+    BLI_split_file_part(split.second.c_str(), file_name, FILE_MAX);
+  }
+  else {
+    BLI_split_file_part(src_path, file_name, FILE_MAX);
+  }
+
+  return file_name;
+}
+
+/* Return true if the given path is an existing director
+ * on the standard file system. */
+static bool fs_parent_dir_exists(const char *path)
+{
+  char dir_path[FILE_MAX];
+  BLI_split_dir_part(path, dir_path, FILE_MAX);
+  bool is_dir = BLI_is_dir(dir_path);
+  return is_dir;
+}
+
+static bool is_udim_path(const std::string &path)
+{
+  return path.find(UDIM_PATTERN) != std::string::npos ||
+         path.find(UDIM_PATTERN2) != std::string::npos;
+}
+
+/* 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()};
+}
+
+static std::string copy_asset_to_directory(const char *src_path, const char *dest_dir_path, bool overwrite)
+{
+  std::string file_name = get_asset_file_name(src_path);
+
+  char dest_file_path[FILE_MAX];
+  BLI_path_join(dest_file_path, FILE_MAX, dest_dir_path, file_name.c_str());
+  BLI_str_replace_char(dest_file_path, SEP, ALTSEP);
+
+  if (!overwrite && BLI_is_file(dest_file_path)) {
+    return dest_file_path;
+  }
+
+  if (!copy_usd_asset(src_path, dest_file_path, overwrite)) {
+    WM_reportf(
+        RPT_WARNING, "usd_import_texture(): Couldn't copy file %s to %s.", src_path, dest_file_path);
+    return src_path;
+  }
+
+  WM_reportf(RPT_INFO, "usd_import_texture(): Copied file %s to %s.", src_path, dest_file_path);
+
+  return dest_file_path;
+}
+
+static std::string copy_udim_asset_to_directory(const char *src_path,
+                                                const char *dest_dir_path,
+                                                bool overwrite)
+{
+  /* Get prefix and suffix from udim pattern. */
+  std::pair<std::string, std::string> splitPath = split_udim_pattern(src_path);
+  if (splitPath.first.empty() || splitPath.second.empty()) {
+    WM_reportf(RPT_ERROR, "copy_udim_asset_to_directory(): Couldn't split UDIM pattern %s.", src_path);
+    return src_path;
+  }
+
+  for (int i = UDIM_START_TILE; i < UDIM_END_TILE; ++i) {
+    const std::string src_udim = splitPath.first + std::to_string(i) + splitPath.second;
+    if (usd_path_exists(src_udim.c_str())) {
+      copy_asset_to_directory(src_udim.c_str(), dest_dir_path, overwrite);
+    }
+  }
+
+  const std::string src_file_name = get_asset_file_name(src_path);
+  char ret_udim_path[FILE_MAX];
+  BLI_path_join(ret_udim_path, FILE_MAX, dest_dir_path, src_file_name.c_str());
+  BLI_str_replace_char(ret_udim_path, SEP, ALTSEP);
+
+  /* Blender only recognizes the <UDIM> pattern, not the
+   * alternative UDIM_PATTERN2, so we make sure the returned
+   * path has the former. */
+  splitPath = split_udim_pattern(ret_udim_path);
+  if (splitPath.first.empty() || splitPath.second.empty()) {
+    WM_reportf(RPT_ERROR, "copy_udim_asset_to_directory(): Couldn't split UDIM pattern %s.", ret_udim_path);
+    return ret_udim_path;
+  }
+
+  return splitPath.first + UDIM_PATTERN + splitPath.second;
+}
+
+
 bool copy_usd_asset(const char *src, const char *dst, bool overwrite)
 {
   if (!(src && dst)) {
@@ -145,4 +269,60 @@ bool copy_usd_asset(const char *src, const char *dst, bool overwrite)
    return resolved_p1 == resolved_p2;
  }
 
+ std::string usd_import_texture(const char *src, const char *import_dir, const bool overwrite)
+ {
+   const bool udim_src = is_udim_path(src);
+
+   if (udim_src) {
+     if (fs_parent_dir_exists(src)) {
+       return src;
+     }
+   }
+   else if (BLI_is_file(src)) {
+     /* File exists in filesystem, no need to import. */
+     return src;
+   }
+
+   if (strlen(import_dir) == 0) {
+     WM_reportf(
+         RPT_ERROR,
+         "usd_import_texture(): Texture import directory path empty, couldn't import %s.",
+         src);
+     return src;
+   }
+
+   char dest_dir_path[FILE_MAX];
+   STRNCPY(dest_dir_path, import_dir);
+
+   if (BLI_path_is_rel(import_dir)) {
+     const char *basepath = BKE_main_blendfile_path_from_global();
+
+     if (!basepath || strlen(basepath) == 0) {
+       WM_reportf(RPT_ERROR,
+                  "usd_import_texture(): Texture import directory is relative "
+                  "but the blend file path is empty.  "
+                  "Please save the blend file before importing the USD. "
+                  "Can't import %s.", src);
+       return src;
+     }
+
+     BLI_path_abs(dest_dir_path, basepath);
+   }
+
+   BLI_str_replace_char(dest_dir_path, SEP, ALTSEP);
+
+   if (!BLI_dir_create_recursive(dest_dir_path)) {
+     WM_reportf(RPT_ERROR,
+                "usd_import_texture(): Couldn't create texture import directory %s.",
+                dest_dir_path);
+     return src;
+   }
+
+   if (udim_src) {
+     return copy_udim_asset_to_directory(src, dest_dir_path, overwrite);
+   }
+
+   return copy_asset_to_directory(src, dest_dir_path, overwrite);
+ }
+
 }  // namespace blender::io::us

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list