[Bf-blender-cvs] [180b66ae8a1] master: UDIM: Support virtual filenames

Jesse Yurkovich noreply at git.blender.org
Mon Jan 3 06:29:34 CET 2022


Commit: 180b66ae8a1ffc0a1bb7d3993028240b4c7f7246
Author: Jesse Yurkovich
Date:   Thu Dec 30 22:06:23 2021 -0800
Branches: master
https://developer.blender.org/rB180b66ae8a1ffc0a1bb7d3993028240b4c7f7246

UDIM: Support virtual filenames

This implements the design detailed in T92696 to support virtual
filenames for UDIM textures. Currently, the following 2 substitution
tokens are supported:

| Token | Meaning |
| ----- | ---- |
| <UDIM>   | 1001 + u-tile + v-tile * 10 |
| <UVTILE> | Equivalent to u<u-tile + 1>_v<v-tile + 1> |

Example for u-tile of 3 and v-tile of 1:
filename.<UDIM>_ver0023.png   --> filename.1014_ver0023.png
filename.<UVTILE>_ver0023.png --> filename.u4_v2_ver0023.png

For image loading, the existing workflow is unchanged. A user can select
one or more image files, belonging to one or more UDIM tile sets, and
have Blender load them all as it does today. Now the <UVTILE> format is
"guessed" just as the <UDIM> format was guessed before.

If guessing fails, the user can simply go into the Image Editor and type
the proper substitution in the filename. Once typing is complete,
Blender will reload the files and correctly fill the tiles. This
workflow is new as attempting to fix the guessing in current versions
did not really work, and the user was often stuck with a confusing
situation.

For image saving, the existing workflow is changed slightly. Currently,
when saving, a user has to be sure to type the filename of the first
tile (e.g. filename.1001.png) to save the entire UDIM set. The number
could differ if they start at a different tile etc. This is confusing.
Now, the user should type a filename containing the appropriate
substitution token. By default Blender will fill in a default name using
the <UDIM> token but the user is free to save out images using <UVTILE>
if they wish.

Differential Revision: https://developer.blender.org/D13057

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

M	intern/cycles/blender/shader.cpp
M	intern/cycles/blender/util.h
M	intern/cycles/scene/image.cpp
M	source/blender/blenkernel/BKE_bpath.h
M	source/blender/blenkernel/BKE_image.h
M	source/blender/blenkernel/intern/bpath.c
M	source/blender/blenkernel/intern/image.c
M	source/blender/blenkernel/intern/image_save.c
M	source/blender/blenlib/BLI_path_util.h
M	source/blender/blenlib/intern/path_util.c
M	source/blender/blenloader/intern/versioning_300.c
M	source/blender/editors/space_file/file_ops.c
M	source/blender/editors/space_file/filesel.c
M	source/blender/editors/space_image/image_ops.c
M	source/blender/editors/space_image/image_sequence.c
M	source/blender/makesdna/DNA_space_types.h

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

diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 70acfce6891..5604c2989fd 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -776,7 +776,7 @@ static ShaderNode *add_node(Scene *scene,
       }
       else {
         ustring filename = ustring(
-            image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
+            image_user_file_path(b_image_user, b_image, b_scene.frame_current()));
         image->set_filename(filename);
       }
     }
@@ -813,7 +813,7 @@ static ShaderNode *add_node(Scene *scene,
       }
       else {
         env->set_filename(
-            ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
+            ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current())));
       }
     }
     node = env;
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
index be36bcdaaa8..6c396d39614 100644
--- a/intern/cycles/blender/util.h
+++ b/intern/cycles/blender/util.h
@@ -33,7 +33,7 @@
 
 extern "C" {
 void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
-void BKE_image_user_file_path(void *iuser, void *ima, char *path);
+void BKE_image_user_file_path_ex(void *iuser, void *ima, char *path, bool resolve_udim);
 unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
 float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
 }
@@ -290,25 +290,14 @@ static inline int render_resolution_y(BL::RenderSettings &b_render)
   return b_render.resolution_y() * b_render.resolution_percentage() / 100;
 }
 
-static inline string image_user_file_path(BL::ImageUser &iuser,
-                                          BL::Image &ima,
-                                          int cfra,
-                                          bool load_tiled)
+static inline string image_user_file_path(BL::ImageUser &iuser, BL::Image &ima, int cfra)
 {
   char filepath[1024];
   iuser.tile(0);
   BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
-  BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
+  BKE_image_user_file_path_ex(iuser.ptr.data, ima.ptr.data, filepath, false);
 
-  string filepath_str = string(filepath);
-  if (load_tiled && ima.source() == BL::Image::source_TILED) {
-    string udim;
-    if (!ima.tiles.empty()) {
-      udim = to_string(ima.tiles[0].number());
-    }
-    string_replace(filepath_str, udim, "<UDIM>");
-  }
-  return filepath_str;
+  return string(filepath);
 }
 
 static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 8bb2d87fd1e..3595ca55a46 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -381,8 +381,15 @@ ImageHandle ImageManager::add_image(const string &filename,
 
   foreach (int tile, tiles) {
     string tile_filename = filename;
+
+    /* Since we don't have information about the exact tile format used in this code location,
+     * just attempt all replacement patterns that Blender supports. */
     if (tile != 0) {
       string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
+
+      int u = ((tile - 1001) % 10);
+      int v = ((tile - 1001) / 10);
+      string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
     }
     const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
     handle.tile_slots.push_back(slot);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index bae151f6a72..bc9e3f01e96 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -49,6 +49,8 @@ typedef enum eBPathForeachFlag {
   BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
   /** Skip paths when their matching data is packed. */
   BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+  /** Resolve tokens within a virtual filepath to a single, concrete, filepath. */
+  BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN = (1 << 3),
   /* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
    * not used as actual source of data by the current .blend file.
    *
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 4db6da4b3ea..0709d05c0d1 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -36,6 +36,7 @@ struct ImageFormatData;
 struct ImagePool;
 struct ImageTile;
 struct ImbFormatOptions;
+struct ListBase;
 struct Main;
 struct Object;
 struct RenderResult;
@@ -284,6 +285,10 @@ void BKE_image_ensure_viewer_views(const struct RenderData *rd,
 void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
 int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
 void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
+void BKE_image_user_file_path_ex(struct ImageUser *iuser,
+                                 struct Image *ima,
+                                 char *path,
+                                 bool resolve_udim);
 void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
 
 /**
@@ -397,6 +402,18 @@ void BKE_image_get_tile_label(struct Image *ima,
                               char *label,
                               int len_label);
 
+/**
+ * Checks whether the given filepath refers to a UDIM tiled texture.
+ * If yes, the range from the lowest to the highest tile is returned.
+ *
+ * `filepath` may be modified to ensure a UDIM token is present.
+ * `tiles` may be filled even if the result ultimately is false!
+ */
+bool BKE_image_get_tile_info(char *filepath,
+                             struct ListBase *tiles,
+                             int *tile_start,
+                             int *tile_range);
+
 struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
 bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
 void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number);
@@ -411,6 +428,40 @@ bool BKE_image_fill_tile(struct Image *ima,
                          int planes,
                          bool is_float);
 
+typedef enum {
+  UDIM_TILE_FORMAT_NONE = 0,
+  UDIM_TILE_FORMAT_UDIM = 1,
+  UDIM_TILE_FORMAT_UVTILE = 2
+} eUDIM_TILE_FORMAT;
+
+/**
+ * Ensures that `filename` contains a UDIM token if we find a supported format pattern.
+ */
+void BKE_image_ensure_tile_token(char *filename);
+
+/**
+ * When provided with an absolute virtual filepath, check to see if at least
+ * one concrete file exists.
+ * Note: This function requires directory traversal and may be inefficient in time-critical,
+ * or iterative, code paths.
+ */
+bool BKE_image_tile_filepath_exists(const char *filepath);
+
+/**
+ * Retrieves the UDIM token format and returns the pattern from the provided `filepath`.
+ * The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or
+ * `BKE_image_set_filepath_from_tile_number`.
+ */
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format);
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+                                             const char *pattern,
+                                             eUDIM_TILE_FORMAT tile_format,
+                                             int *r_tile_number);
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+                                             const char *pattern,
+                                             eUDIM_TILE_FORMAT tile_format,
+                                             int tile_number);
+
 struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
 struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
 
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 85e49774dfd..44ef3ec96ff 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -236,7 +236,8 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
   BKE_bpath_foreach_path_main(&(BPathForeachPathData){
       .bmain = bmain,
       .callback_function = check_missing_files_foreach_path_cb,
-      .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED,
+      .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED |
+              BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN,
       .user_data = reports});
 }
 
@@ -384,7 +385,8 @@ void BKE_bpath_missing_files_find(Main *bmain,
                                   const bool find_all)
 {
   struct BPathFind_Data data = {NULL};
-  const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED;
+  const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED |
+                   BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN;
 
   data.basedir = BKE_main_blendfile_path(bmain);
   data.reports = reports;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 3fec5db422d..2d4366846aa 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -21,6 +21,7 @@
  * \ingroup bke
  */
 
+#include <ctype.h>
 #include <fcntl.h>
 #include <math.h>
 #include <stdio.h>
@@ -272,7 +273,33 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
     return;
   }
 
-  if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
+  /* If this is a tiled image, and we're asked to resolve the tokens in the virtual
+   * filepath, use the first tile to generate a concrete path for use during processing. */
+  bool result = false;
+  if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) {
+    char temp_path[FILE_MAX], orig_file[FILE_MAXFILE];
+    BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path));
+    BLI_split_fi

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list