diff options
Diffstat (limited to 'source/blender/io/usd/intern')
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_material.cc | 81 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_mesh.cc | 54 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_mesh.h | 9 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_writer_mesh.cc | 15 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_writer_volume.cc | 2 |
5 files changed, 135 insertions, 26 deletions
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("<UDIM>") != std::string::npos; +} + +/* For the given UDIM path (assumed to contain the UDIM token), returns an array + * containing valid tile indices. */ +static blender::Vector<int> 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<int> 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<int> &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) @@ -601,11 +658,31 @@ 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 (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<int> 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. diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 45657525527..89a98097780 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -6,6 +6,7 @@ #include "usd_reader_mesh.h" #include "usd_reader_material.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_main.h" #include "BKE_material.h" @@ -64,12 +65,26 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> * static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim) { - return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial(); + pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim); + + /* Compute generically bound ('allPurpose') materials. */ + pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial(); + + /* If no generic material could be resolved, also check for 'preview' and + * 'full' purpose materials as fallbacks. */ + if (!mtl) { + mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview); + } + + if (!mtl) { + mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full); + } + + return mtl; } -/* Returns an existing Blender material that corresponds to the USD - * material with with the given path. Returns null if no such material - * exists. */ +/* Returns an existing Blender material that corresponds to the USD material with the given path. + * Returns null if no such material exists. */ static Material *find_existing_material( const pxr::SdfPath &usd_mat_path, const USDImportParams ¶ms, @@ -193,7 +208,8 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type /* Create a new layer. */ numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); + cd_ptr = CustomData_add_layer_named( + loopdata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -304,7 +320,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh) MPoly &poly = mpolys[i]; poly.loopstart = loop_index; poly.totloop = face_size; - poly.mat_nr = 0; /* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded, * this is encoded in custom loop normals. */ @@ -562,7 +577,7 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim } float *creases = static_cast<float *>( - CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert)); for (size_t i = 0; i < corner_indices.size(); i++) { creases[corner_indices[i]] = corner_sharpnesses[i]; @@ -720,10 +735,9 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings, } } -void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, - MPoly *mpoly, - const int /* totpoly */, - std::map<pxr::SdfPath, int> *r_mat_map) +void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime, + MutableSpan<int> material_indices, + std::map<pxr::SdfPath, int> *r_mat_map) { if (r_mat_map == nullptr) { return; @@ -763,9 +777,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, pxr::VtIntArray indices; indicesAttribute.Get(&indices, motionSampleTime); - for (int i = 0; i < indices.size(); i++) { - MPoly &poly = mpoly[indices[i]]; - poly.mat_nr = mat_idx; + for (const int i : indices) { + material_indices[i] = mat_idx; } } } @@ -790,7 +803,12 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot } std::map<pxr::SdfPath, int> mat_map; - assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map); + + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); + material_indices.finish(); /* Build material name map if it's not built yet. */ if (this->settings_->mat_name_to_mat.empty()) { utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat); @@ -896,7 +914,11 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, size_t num_polys = active_mesh->totpoly; if (num_polys > 0 && import_params_.import_materials) { std::map<pxr::SdfPath, int> mat_map; - assign_facesets_to_mpoly(motionSampleTime, active_mesh->mpoly, num_polys, &mat_map); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*active_mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); + material_indices.finish(); } } diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index 5e33ce8b5e8..9a3b0565668 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -3,6 +3,8 @@ * Modifications Copyright 2021 Tangent Animation and. NVIDIA Corporation. All rights reserved. */ #pragma once +#include "BLI_span.hh" + #include "usd.h" #include "usd_reader_geom.h" @@ -61,10 +63,9 @@ class USDMeshReader : public USDGeomReader { /** Set USD uniform (per-face) normals as Blender loop normals. */ void process_normals_uniform(Mesh *mesh); void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime); - void assign_facesets_to_mpoly(double motionSampleTime, - struct MPoly *mpoly, - int totpoly, - std::map<pxr::SdfPath, int> *r_mat_map); + void assign_facesets_to_material_indices(double motionSampleTime, + MutableSpan<int> material_indices, + std::map<pxr::SdfPath, int> *r_mat_map); void read_mpolys(Mesh *mesh); void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false); diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index b76f74cfd3d..ade75fdb365 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -11,6 +11,7 @@ #include "BLI_math_vector.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" @@ -255,7 +256,15 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data) { /* Only construct face groups (a.k.a. geometry subsets) when we need them for material * assignments. */ - bool construct_face_groups = mesh->totcol > 1; + const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (!material_indices.is_single() && mesh->totcol > 1) { + const VArraySpan<int> indices_span(material_indices); + for (const int i : indices_span.index_range()) { + usd_mesh_data.face_groups[indices_span[i]].push_back(i); + } + } usd_mesh_data.face_vertex_counts.reserve(mesh->totpoly); usd_mesh_data.face_indices.reserve(mesh->totloop); @@ -268,10 +277,6 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data) for (int j = 0; j < mpoly->totloop; ++j, ++loop) { usd_mesh_data.face_indices.push_back(loop->v); } - - if (construct_face_groups) { - usd_mesh_data.face_groups[mpoly->mat_nr].push_back(i); - } } } diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc index 6300e5c657c..12db6d73901 100644 --- a/source/blender/io/usd/intern/usd_writer_volume.cc +++ b/source/blender/io/usd/intern/usd_writer_volume.cc @@ -152,7 +152,7 @@ std::optional<std::string> USDVolumeWriter::construct_vdb_file_path(const Volume strcat(vdb_file_name, ".vdb"); char vdb_file_path[FILE_MAX]; - BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name, NULL); + BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name, nullptr); return vdb_file_path; } |