From 4655ddf3a2b7fee669f7d01f6f70d5f3711205c6 Mon Sep 17 00:00:00 2001 From: Michael Kowalski Date: Thu, 4 Aug 2022 11:30:48 -0400 Subject: T90535: import UDIM textures from USD Added logic to the USD Preview Surface importer to convert UDIM textures. Reviewed by: Sybren and Jesse Differential Revision: https://developer.blender.org/D15379 --- .../blender/io/usd/intern/usd_reader_material.cc | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'source/blender/io/usd/intern') diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index 8feceee55ed..f59b8be147e 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -9,8 +9,11 @@ #include "BKE_node.h" #include "BKE_node_tree_update.h" +#include "BLI_fileops.h" #include "BLI_math_vector.h" +#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_vector.hh" #include "DNA_material_types.h" @@ -94,6 +97,60 @@ 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(); +} + +static bool is_udim_path(const std::string &path) +{ + return path.find("") != std::string::npos; +} + +/* For the given UDIM path (assumed to contain the UDIM token), returns an array + * containing valid tile indices. */ +static blender::Vector get_udim_tiles(const std::string &file_path) +{ + char base_udim_path[FILE_MAX]; + BLI_strncpy(base_udim_path, file_path.c_str(), sizeof(base_udim_path)); + + blender::Vector udim_tiles; + + /* Extract the tile numbers from all files on disk. */ + ListBase tiles = {nullptr, nullptr}; + int tile_start, tile_range; + bool result = BKE_image_get_tile_info(base_udim_path, &tiles, &tile_start, &tile_range); + if (result) { + LISTBASE_FOREACH (LinkData *, tile, &tiles) { + int tile_number = POINTER_AS_INT(tile->data); + udim_tiles.append(tile_number); + } + } + + BLI_freelistN(&tiles); + + return udim_tiles; +} + +/* Add tiles with the given indices to the given image. */ +static void add_udim_tiles(Image *image, const blender::Vector &indices) +{ + image->source = IMA_SRC_TILED; + + for (int tile_number : indices) { + BKE_image_add_tile(image, tile_number, nullptr); + } +} + /* Returns true if the given shader may have opacity < 1.0, based * on heuristics. */ static bool needs_blend(const pxr::UsdShadeShader &usd_shader) @@ -600,12 +657,32 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader, const pxr::SdfAssetPath &asset_path = file_val.Get(); 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 (file_path.empty()) { std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path << "' for Texture Image node." << std::endl; return; } + /* If this is a UDIM texture, this will store the + * UDIM tile indices. */ + blender::Vector udim_tiles; + + if (is_udim_path(file_path)) { + udim_tiles = get_udim_tiles(file_path); + } + const char *im_file = file_path.c_str(); Image *image = BKE_image_load_exists(bmain_, im_file); if (!image) { @@ -614,6 +691,10 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader, return; } + if (udim_tiles.size() > 0) { + add_udim_tiles(image, udim_tiles); + } + tex_image->id = &image->id; /* Set texture color space. -- cgit v1.2.3