[Bf-blender-cvs] [05c4982f712] temp-T90535-usd-alab-material-import: USD Preview Surface material import improvements.

Michael Kowalski noreply at git.blender.org
Fri Nov 19 20:05:30 CET 2021


Commit: 05c4982f712be287b901713e6d8cfc0cbc208696
Author: Michael Kowalski
Date:   Fri Nov 19 13:48:02 2021 -0500
Branches: temp-T90535-usd-alab-material-import
https://developer.blender.org/rB05c4982f712be287b901713e6d8cfc0cbc208696

USD Preview Surface material import improvements.

Updates to address issues importing USD Preview Surface
materials in Animal Logic's ALab scene, as described in
T90535:

Added support for importing UDIM textures.

Added 'Material Name Collision' USD import menu option,
to specify the behavior when USD materials in different
namespaces have the same name.  The options are

Modify: Create a unique name for the imported material.
Skip: Keep the existing material and discard the imported material.

Previously, the default behavior was Skip.  This was causing an
issue in the Alab scene, where dozens of different USD materials
all have the same name 'usdpreviewsurface1', so that only one
instance of these materials would be imported.

Finally, if no materials with purpose "render" are assigned to
the USD primitive, the importer will now fall back on converting
assigned materials with purpose "preview".

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/intern/usd_reader_material.cc
M	source/blender/io/usd/intern/usd_reader_mesh.cc
M	source/blender/io/usd/intern/usd_reader_prim.h
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 4e2ccea36ab..39f09014a61 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -73,6 +73,20 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
     {0, NULL, 0, NULL, NULL},
 };
 
+const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
+    {USD_MTL_NAME_COLLISION_MODIFY,
+     "MODIFY",
+     0,
+     "Modify",
+     "Create a unique name for the imported material"},
+    {USD_MTL_NAME_COLLISION_SKIP,
+     "SKIP",
+     0,
+     "Skip",
+     "Keep the existing material and discard the imported material"},
+    {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 };
@@ -318,6 +332,9 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
 
   const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale");
 
+  const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr,
+                                                                        "mtl_name_collision_mode");
+
   /* TODO(makowalski): Add support for sequences. */
   const bool is_sequence = false;
   int offset = 0;
@@ -356,7 +373,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
                                    .use_instancing = use_instancing,
                                    .import_usd_preview = import_usd_preview,
                                    .set_material_blend = set_material_blend,
-                                   .light_intensity_scale = light_intensity_scale};
+                                   .light_intensity_scale = light_intensity_scale,
+                                   .mtl_name_collision_mode = mtl_name_collision_mode};
 
   const bool ok = USD_import(C, filename, &params, as_background_job);
 
@@ -399,6 +417,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   uiItemR(col, ptr, "relative_path", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "create_collection", 0, NULL, ICON_NONE);
   uiItemR(box, ptr, "light_intensity_scale", 0, NULL, ICON_NONE);
+  uiItemR(box, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE);
 
   box = uiLayoutBox(layout);
   col = uiLayoutColumnWithHeading(box, true, IFACE_("Experimental"));
@@ -519,6 +538,13 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
                 "Scale for the intensity of imported lights",
                 0.0001f,
                 1000.0f);
+
+  RNA_def_enum(ot->srna,
+               "mtl_name_collision_mode",
+               rna_enum_usd_mtl_name_collision_mode_items,
+               USD_MTL_NAME_COLLISION_MODIFY,
+               "Material Name Collision",
+               "Behavior when the name of an imported material conflicts with an existing material");
 }
 
 #endif /* WITH_USD */
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index 317dfd2a62b..c09b8ee1e2d 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -24,7 +24,9 @@
 #include "BKE_material.h"
 #include "BKE_node.h"
 
+#include "BLI_fileops.h"
 #include "BLI_math_vector.h"
+#include "BLI_path_util.h"
 #include "BLI_string.h"
 
 #include "DNA_material_types.h"
@@ -109,6 +111,132 @@ static void link_nodes(
   nodeAddLink(ntree, source, source_socket, dest, dest_socket);
 }
 
+/* Returns a layer handle retrieved from the given attribute's property specs.
+ * Note that the returned handle may be invalid if no layer could be found. */
+static pxr::SdfLayerHandle get_layer_handle(const pxr::UsdAttribute &Attribute)
+{
+  for (auto PropertySpec : Attribute.GetPropertyStack(pxr::UsdTimeCode::EarliestTime())) {
+    if (PropertySpec->HasDefaultValue() ||
+        PropertySpec->GetLayer()->GetNumTimeSamplesForPath(PropertySpec->GetPath()) > 0) {
+      return PropertySpec->GetLayer();
+    }
+  }
+
+  return pxr::SdfLayerHandle();
+}
+
+/* If the given file path contains a UDIM token, examine files
+ * on disk to determine the indices of the UDIM tiles that are available
+ * to load.  Returns the path to the file corresponding to the lowest tile
+ * index and an array containing valid tile indices in 'r_first_tile_path'
+ * and 'r_tile_indices', respctively.  The function returns true if the
+ * given arguments are valid, if 'file_path' is a UDIM path and
+ * if any tiles were found on disk; it returns false otherwise. */
+static bool get_udim_tiles(const std::string &file_path,
+                           std::string *r_first_tile_path,
+                           std::vector<int> *r_tile_indices)
+{
+  if (file_path.empty()) {
+    return false;
+  }
+
+  if (!(r_first_tile_path && r_tile_indices)) {
+    return false;
+  }
+
+  /* Check if we have a UDIM path. */
+  std::size_t udim_token_offset = file_path.find("<UDIM>");
+
+  if (udim_token_offset == std::string::npos) {
+    /* No UDIM token. */
+    return false;
+  }
+
+  /* Create a dummy UDIM path by replacing the '<UDIM>' token
+   * with an arbitrary index, since this is the format expected
+   * as input to the call BLI_path_sequence_decode().  We use the
+   * index 1001, but this will be rplaced by the actual index
+   * of the first tile found on disk. */
+  std::string base_udim_path(file_path);
+  base_udim_path.replace(udim_token_offset, 6, "1001");
+
+  /* Exctract the file and directory names from the path. */
+  char filename[FILE_MAX], dirname[FILE_MAXDIR];
+  BLI_split_dirfile(base_udim_path.c_str(), dirname, filename, sizeof(dirname), sizeof(filename));
+
+  /* Split the base and head portions of the file name. */
+  ushort digits = 0;
+  char base_head[FILE_MAX], base_tail[FILE_MAX];
+  base_head[0] = '\0';
+  base_tail[0] = '\0';
+  int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
+
+  /* As a sanity check, confirm that we got our original index. */
+  if (id != 1001) {
+    return false;
+  }
+
+  /* Iterate over the directory contents to find files
+   * with matching names and with the expected index format
+   * for UDIMS. */
+  struct direntry *dir = nullptr;
+  uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+
+  if (!dir) {
+    return false;
+  }
+
+  for (int i = 0; i < totfile; ++i) {
+    if (!(dir[i].type & S_IFREG)) {
+      continue;
+    }
+
+    char head[FILE_MAX], tail[FILE_MAX];
+    head[0] = '\0';
+    tail[0] = '\0';
+    int id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
+
+    if (digits == 0 || digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
+      !(STREQLEN(base_tail, tail, FILE_MAX))) {
+      continue;
+    }
+
+    if (id < 1001 || id >= IMA_UDIM_MAX) {
+      continue;
+    }
+
+    r_tile_indices->push_back(id);
+  }
+
+  BLI_filelist_free(dir, totfile);
+
+  if (r_tile_indices->empty()) {
+    return false;
+  }
+
+  std::sort(r_tile_indices->begin(), r_tile_indices->end());
+
+  /* Finally, use the lowest index we found to create the first tile path. */
+  (*r_first_tile_path) = file_path;
+  r_first_tile_path->replace(udim_token_offset, 6, std::to_string(r_tile_indices->front()));
+
+  return true;
+}
+
+/* Add tiles with the given indices to the given image. */
+static void add_udim_tiles(Image *image, const std::vector<int> &indices)
+{
+  if (!image || indices.empty()) {
+    return;
+  }
+
+  image->source = IMA_SRC_TILED;
+
+  for (int i = 0; i < indices.size(); ++i) {
+    BKE_image_add_tile(image, indices[i], nullptr);
+  }
+}
+
 /* Returns true if the given shader may have opacity < 1.0, based
  * on heuristics. */
 static bool needs_blend(const pxr::UsdShadeShader &usd_shader)
@@ -621,6 +749,23 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
 
   const pxr::SdfAssetPath &asset_path = file_val.Get<pxr::SdfAssetPath>();
   std::string file_path = asset_path.GetResolvedPath();
+  if (file_path.empty()) {
+    /* No resolved path, so use the asset path (usually
+     * necessary for UDIM paths). */
+    file_path = asset_path.GetAssetPath();
+
+    /* Texture paths are frequently relative to the USD, so get
+     * the absolute path. */
+    if (pxr::SdfLayerHandle layer_handle = get_layer_handle(file_input.GetAttr())) {
+      file_path = layer_handle->ComputeAbsolutePath(file_path);
+    }
+  }
+
+  /* If this is a UDIM texture, this array will store the
+   * UDIM tile indices. */
+  std::vector<int> udim_tile_indices;
+  get_udim_tiles(file_path, &file_path, &udim_tile_indices);
+
   if (file_path.empty()) {
     std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path
               << "' for Texture Image node." << std::endl;
@@ -635,6 +780,10 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
     return;
   }
 
+  if (!udim_tile_indices.empty()) {
+    add_udim_tiles(image, udim_tile_indices);
+  }
+
   tex_image->id = &image->id;
 
   /* Set texture color space.
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 5c8bd88e87a..a7cd0d07d72 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -80,41 +80,61 @@ static void assign_materials(Main *bmain,
                              Object *ob,
                              const std::map<pxr::SdfPath, int> &mat_index_map,
                              const USDImportParams &params,
-                             pxr::UsdStageRefPtr stage)
+                             pxr::UsdStageRefPtr stage,
+                             std::map<std::string, std::string> &usd_path_to_mat_name)
 {
   if (!(stage && bmain && ob)) {
     return;
   }
 
-  bool can_assign = true;
   std::map<pxr::SdfPath, int>::const_iterator it = mat_index_map.begin();
 
-  int matcount = 0;
-  for (; it != mat_index_map.end(); ++it, matcount++) {
+  for (; it != mat_index_map.end(); ++it) {
     if (!BKE_object_material_slot_add(bmain, ob)) {
-      can_assign = f

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list