Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/io/io_usd.c29
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc86
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h10
-rw-r--r--source/blender/io/usd/usd.h8
4 files changed, 112 insertions, 21 deletions
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 45d658d5b25..a59cdf60243 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -57,6 +57,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_MAKE_UNIQUE,
+ "MAKE_UNIQUE",
+ 0,
+ "Make Unique",
+ "Import each USD material as a unique Blender material"},
+ {USD_MTL_NAME_COLLISION_REFERENCE_EXISTING,
+ "REFERENCE_EXISTING",
+ 0,
+ "Reference Existing",
+ "If a material with the same name already exists, reference that instead of importing"},
+ {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 };
@@ -371,6 +385,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;
@@ -409,7 +426,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);
@@ -452,6 +470,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"));
@@ -575,6 +594,14 @@ 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_MAKE_UNIQUE,
+ "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_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 2c86bfff4da..368d0e1bab9 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -62,11 +62,56 @@ 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();
+}
+
+/* Returns an existing Blender material that corresponds to the USD
+ * material with with the given path. Returns null if no such material
+ * exists. */
+static Material *find_existing_material(
+ const pxr::SdfPath &usd_mat_path,
+ const USDImportParams &params,
+ const std::map<std::string, Material *> &mat_map,
+ const std::map<std::string, std::string> &usd_path_to_mat_name)
+{
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Check if we've already created the Blender material with a modified name. */
+ std::map<std::string, std::string>::const_iterator path_to_name_iter =
+ usd_path_to_mat_name.find(usd_mat_path.GetAsString());
+
+ if (path_to_name_iter != usd_path_to_mat_name.end()) {
+ std::string mat_name = path_to_name_iter->second;
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ else {
+ /* We can't find the Blender material which was previously created for this USD
+ * material, which should never happen. */
+ BLI_assert_unreachable();
+ }
+ }
+ }
+ else {
+ std::string mat_name = usd_mat_path.GetName();
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ }
+
+ return nullptr;
+}
+
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;
@@ -94,13 +139,10 @@ static void assign_materials(Main *bmain,
blender::io::usd::USDMaterialReader mat_reader(params, bmain);
for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
- std::string mat_name = it->first.GetName();
-
- std::map<std::string, Material *>::iterator mat_iter = mat_map.find(mat_name);
-
- Material *assigned_mat = nullptr;
- if (mat_iter == mat_map.end()) {
+ Material *assigned_mat = find_existing_material(
+ it->first, params, mat_map, usd_path_to_mat_name);
+ if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
/* Look up the USD material. */
@@ -122,11 +164,14 @@ static void assign_materials(Main *bmain,
continue;
}
+ const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2);
mat_map[mat_name] = assigned_mat;
- }
- else {
- /* We found an existing Blender material. */
- assigned_mat = mat_iter->second;
+
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Record the name of the Blender material we created for the USD material
+ * with the given path. */
+ usd_path_to_mat_name[it->first.GetAsString()] = mat_name;
+ }
}
if (assigned_mat) {
@@ -134,7 +179,7 @@ static void assign_materials(Main *bmain,
}
else {
/* This shouldn't happen. */
- std::cout << "WARNING: Couldn't assign material " << mat_name << std::endl;
+ std::cout << "WARNING: Couldn't assign material " << it->first << std::endl;
}
}
}
@@ -710,11 +755,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
int current_mat = 0;
if (!subsets.empty()) {
for (const pxr::UsdGeomSubset &subset : subsets) {
- pxr::UsdShadeMaterialBindingAPI subset_api = pxr::UsdShadeMaterialBindingAPI(
- subset.GetPrim());
-
- pxr::UsdShadeMaterial subset_mtl = subset_api.ComputeBoundMaterial();
+ pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim());
if (!subset_mtl) {
continue;
}
@@ -743,10 +785,9 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
}
if (r_mat_map->empty()) {
- pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim_);
-
- if (pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial()) {
+ pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_);
+ if (mtl) {
pxr::SdfPath mtl_path = mtl.GetPath();
if (!mtl_path.IsEmpty()) {
@@ -764,7 +805,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);
- utils::assign_materials(bmain, object_, mat_map, this->import_params_, this->prim_.GetStage());
+ utils::assign_materials(bmain,
+ object_,
+ mat_map,
+ this->import_params_,
+ this->prim_.GetStage(),
+ this->settings_->usd_path_to_mat_name);
}
Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h
index fdf6247de16..f2df00accf6 100644
--- a/source/blender/io/usd/intern/usd_reader_prim.h
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -7,6 +7,9 @@
#include <pxr/usd/usd/prim.h>
+#include <map>
+#include <string>
+
struct Main;
struct Object;
@@ -33,6 +36,13 @@ struct ImportSettings {
CacheFile *cache_file;
+ /* Map a USD material prim path to a Blender material name.
+ * This map is updated by readers during stage traversal.
+ * This field is mutable because it is used to keep track
+ * of what the importer is doing. This is necessary even
+ * when all the other import settings are to remain const. */
+ mutable std::map<std::string, std::string> usd_path_to_mat_name;
+
ImportSettings()
: do_convert_mat(false),
from_up(0),
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 2e4dcb0da94..a07315d8b4e 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -15,6 +15,13 @@ struct CacheReader;
struct Object;
struct bContext;
+/* Behavior when the name of an imported material
+ * conflicts with an existing material. */
+typedef enum eUSDMtlNameCollisionMode {
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE = 0,
+ USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1,
+} eUSDMtlNameCollisionMode;
+
struct USDExportParams {
bool export_animation;
bool export_hair;
@@ -57,6 +64,7 @@ struct USDImportParams {
bool import_usd_preview;
bool set_material_blend;
float light_intensity_scale;
+ eUSDMtlNameCollisionMode mtl_name_collision_mode;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.