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:
authorMichael Kowalski <makowalski@nvidia.com>2022-10-06 06:06:21 +0300
committerMichael Kowalski <makowalski@nvidia.com>2022-10-06 06:06:21 +0300
commit05e8eeda3c95c960b2481b85cd836194d78c95ad (patch)
tree07b2883339bb84e865ae1cccdd9cf76f1b7b1262 /source/blender
parenta096248d1253e5a4436fbc4c2fc1d51539183fc0 (diff)
USD import unbound materials.
This addresses issue T97195. Added a new Unbound Materials USD import option, to import materials not assigned to any geometry.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/io/io_usd.c9
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc8
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc48
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.h29
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc40
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc72
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.h4
-rw-r--r--source/blender/io/usd/usd.h1
8 files changed, 172 insertions, 39 deletions
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index eb80cabcd7f..5fe8ff7a16c 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -381,6 +381,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
const bool import_proxy = RNA_boolean_get(op->ptr, "import_proxy");
const bool import_render = RNA_boolean_get(op->ptr, "import_render");
+ const bool import_unbound_materials = RNA_boolean_get(op->ptr, "import_unbound_materials");
+
const bool import_usd_preview = RNA_boolean_get(op->ptr, "import_usd_preview");
const bool set_material_blend = RNA_boolean_get(op->ptr, "set_material_blend");
@@ -427,7 +429,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
.import_usd_preview = import_usd_preview,
.set_material_blend = set_material_blend,
.light_intensity_scale = light_intensity_scale,
- .mtl_name_collision_mode = mtl_name_collision_mode};
+ .mtl_name_collision_mode = mtl_name_collision_mode,
+ .import_unbound_materials = import_unbound_materials};
STRNCPY(params.prim_path_mask, prim_path_mask);
@@ -471,6 +474,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(col, ptr, "import_guide", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "import_proxy", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "import_render", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "import_unbound_materials", 0, NULL, ICON_NONE);
col = uiLayoutColumnWithHeading(box, true, IFACE_("Options"));
uiItemR(col, ptr, "set_frame_range", 0, NULL, ICON_NONE);
@@ -579,6 +583,9 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "import_render", true, "Render", "Import final render geometry");
+ RNA_def_boolean(ot->srna, "import_unbound_materials", false,
+ "Unbound Materials", "Include materials not bound to any geometry");
+
RNA_def_boolean(ot->srna,
"import_usd_preview",
false,
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 5808c6bc77a..29f3792792b 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -225,8 +225,16 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
data->archive = archive;
+ if (data->params.import_unbound_materials) {
+ archive->import_all_materials(data->bmain);
+ }
+
archive->collect_readers(data->bmain);
+ if (data->params.import_unbound_materials) {
+ archive->fake_users_for_unbound_materials();
+ }
+
*data->do_update = true;
*data->progress = 0.2f;
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index d1af4553083..6416f6861d4 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -757,4 +757,52 @@ void USDMaterialReader::convert_usd_primvar_reader_float2(
link_nodes(ntree, uv_map, "UV", dest_node, dest_socket_name);
}
+
+void build_material_map(const Main *bmain, std::map<std::string, Material *> *r_mat_map)
+{
+ if (r_mat_map == nullptr) {
+ return;
+ }
+
+ Material *material = static_cast<Material *>(bmain->materials.first);
+
+ for (; material; material = static_cast<Material *>(material->id.next)) {
+ (*r_mat_map)[pxr::TfMakeValidIdentifier(material->id.name + 2)] = material;
+ }
+}
+
+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;
+ }
+ /* 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;
+}
+
} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h
index 24d80e99c38..abd810b9936 100644
--- a/source/blender/io/usd/intern/usd_reader_material.h
+++ b/source/blender/io/usd/intern/usd_reader_material.h
@@ -6,6 +6,8 @@
#include <pxr/usd/usdShade/material.h>
+#include <map>
+
struct Main;
struct Material;
struct bNode;
@@ -69,6 +71,7 @@ class USDMaterialReader {
Main *bmain_;
public:
+
USDMaterialReader(const USDImportParams &params, Main *bmain);
Material *add_material(const pxr::UsdShadeMaterial &usd_material) const;
@@ -129,4 +132,30 @@ class USDMaterialReader {
NodePlacementContext *r_ctx) const;
};
+/* Utility functions. */
+
+/**
+ * Returns a map containing all the Blender materials which allows a fast
+ * lookup of the material object by name. Note that the material name key
+ * might be modified to be a valid USD identifier, to match materials
+ * imported from USD.
+ */
+void build_material_map(const Main *bmain, std::map<std::string, Material *> *r_mat_map);
+
+/**
+ * Returns an existing Blender material that corresponds to the USD material with the given path.
+ * Returns null if no such material exists.
+ *
+ * \param mat_map Map a Blender material name to the material object.
+ * \param usd_path_to_mat_name Map a USD material path to the imported Blender material name.
+ *
+ * The usd_path_to_mat_name is needed to determine the name of the Blender
+ * material imported from a USD path in the case when a unique name was generated
+ * for the material due to a name collision.
+ */
+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);
+
} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 77c79852141..3dbdd5d486b 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -83,42 +83,6 @@ static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
return mtl;
}
-/* 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 &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;
- }
- /* 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,
@@ -141,7 +105,7 @@ static void assign_materials(Main *bmain,
it != mat_index_map.end();
++it) {
- Material *assigned_mat = find_existing_material(
+ Material *assigned_mat = blender::io::usd::find_existing_material(
it->first, params, mat_name_to_mat, usd_path_to_mat_name);
if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
@@ -810,7 +774,7 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
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);
+ build_material_map(bmain, &this->settings_->mat_name_to_mat);
}
utils::assign_materials(bmain,
object_,
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
index df75be849e2..89dd7098f6c 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.cc
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -5,6 +5,7 @@
#include "usd_reader_camera.h"
#include "usd_reader_curve.h"
#include "usd_reader_light.h"
+#include "usd_reader_material.h"
#include "usd_reader_mesh.h"
#include "usd_reader_nurbs.h"
#include "usd_reader_prim.h"
@@ -12,12 +13,14 @@
#include "usd_reader_xform.h"
#include <pxr/pxr.h>
+#include <pxr/usd/usd/primRange.h>
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdGeom/curves.h>
#include <pxr/usd/usdGeom/mesh.h>
#include <pxr/usd/usdGeom/nurbsCurves.h>
#include <pxr/usd/usdGeom/scope.h>
#include <pxr/usd/usdGeom/xform.h>
+#include <pxr/usd/usdShade/material.h>
#if PXR_VERSION >= 2111
# include <pxr/usd/usdLux/boundableLightBase.h>
@@ -31,6 +34,10 @@
#include "BLI_sort.hh"
#include "BLI_string.h"
+#include "BKE_lib_id.h"
+
+#include "DNA_material_types.h"
+
namespace blender::io::usd {
USDStageReader::USDStageReader(pxr::UsdStageRefPtr stage,
@@ -294,6 +301,71 @@ void USDStageReader::collect_readers(Main *bmain)
collect_readers(bmain, root);
}
+/* Iterate through stage and import each material prim. */
+void USDStageReader::import_all_materials(Main *bmain)
+{
+ if (!valid()) {
+ return;
+ }
+
+ /* Build the material name map if it's not built yet. */
+ if (settings_.mat_name_to_mat.empty()) {
+ build_material_map(bmain, &settings_.mat_name_to_mat);
+ }
+
+ USDMaterialReader mtl_reader(params_, bmain);
+
+ PXR_NS::UsdPrimRange range = stage_->TraverseAll();
+ for (const auto &prim : range) {
+ if (prim.IsA<pxr::UsdShadeMaterial>()) {
+ pxr::UsdShadeMaterial usd_mtl(prim);
+ if (!usd_mtl) {
+ continue;
+ }
+
+ Material *blend_mtl = blender::io::usd::find_existing_material(
+ prim.GetPath(), params_, settings_.mat_name_to_mat, settings_.usd_path_to_mat_name);
+
+ if (blend_mtl) {
+ /* The material already exists. */
+ continue;
+ }
+
+ /* Add the material now. */
+ if (blend_mtl = mtl_reader.add_material(usd_mtl)) {
+
+ 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, so we don't import the material again if the
+ * material is shared. */
+ const std::string mtl_name = pxr::TfMakeValidIdentifier(blend_mtl->id.name + 2);
+ settings_.mat_name_to_mat[mtl_name] = blend_mtl;
+
+ settings_.usd_path_to_mat_name[prim.GetPath().GetAsString()] = mtl_name;
+ }
+ }
+ }
+ }
+}
+
+/* Add fake users for any imported materials with
+ * no users. This is typically required for unbound
+ * materials. */
+void USDStageReader::fake_users_for_unbound_materials()
+{
+ std::map<std::string, std::string>::const_iterator mat_name_it = settings_.usd_path_to_mat_name.begin();
+ for (; mat_name_it != settings_.usd_path_to_mat_name.end(); ++mat_name_it) {
+ std::map<std::string, Material *>::iterator mat_it = settings_.mat_name_to_mat.find(
+ mat_name_it->second);
+ if (mat_it != settings_.mat_name_to_mat.end()) {
+ Material *mat = mat_it->second;
+ if (mat->id.us == 0) {
+ id_fake_user_set(&mat->id);
+ }
+ }
+ }
+}
+
void USDStageReader::clear_readers()
{
for (USDPrimReader *reader : readers_) {
diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h
index 5f4a343f874..8ad84ddb372 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.h
+++ b/source/blender/io/usd/intern/usd_reader_stage.h
@@ -40,6 +40,10 @@ class USDStageReader {
void collect_readers(struct Main *bmain);
+ void import_all_materials(struct Main *bmain);
+
+ void fake_users_for_unbound_materials();
+
bool valid() const;
pxr::UsdStageRefPtr stage()
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 3494d8ffdc3..19b6770b101 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -65,6 +65,7 @@ struct USDImportParams {
bool set_material_blend;
float light_intensity_scale;
eUSDMtlNameCollisionMode mtl_name_collision_mode;
+ bool import_unbound_materials;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.