[Bf-blender-cvs] [3c79e1cb896] usd-importer-T81257: USD material import initial implementation.

Michael A. Kowalski noreply at git.blender.org
Fri Oct 23 17:49:44 CEST 2020


Commit: 3c79e1cb8960c10efa31967a03afb75ca5cea2ae
Author: Michael A. Kowalski
Date:   Thu Oct 22 21:58:58 2020 -0400
Branches: usd-importer-T81257
https://developer.blender.org/rB3c79e1cb8960c10efa31967a03afb75ca5cea2ae

USD material import initial implementation.

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

M	source/blender/editors/io/io_usd.c
M	source/blender/io/usd/import/usd_reader_mesh.cc
M	source/blender/io/usd/import/usd_reader_mesh.h
M	source/blender/io/usd/usd.h

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

diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 9f82e9a2849..c223e22bc46 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -271,6 +271,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
 
   const bool import_normals = RNA_boolean_get(op->ptr, "import_normals");
 
+  const bool import_materials = RNA_boolean_get(op->ptr, "import_materials");
+
   const float scale = RNA_float_get(op->ptr, "scale");
 
   const bool debug = RNA_boolean_get(op->ptr, "debug");
@@ -281,7 +283,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
     ED_object_mode_set(C, OB_MODE_OBJECT);
   }
 
-  struct USDImportParams params = {import_uvs, import_normals, scale, debug};
+  struct USDImportParams params = {import_uvs, import_normals, import_materials, scale, debug};
 
   bool ok = USD_import(C, filename, &params, as_background_job);
 
@@ -303,6 +305,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
   col = uiLayoutColumn(box, true);
   uiItemR(col, ptr, "import_uvs", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "import_normals", 0, NULL, ICON_NONE);
+  uiItemR(col, ptr, "import_materials", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "debug", 0, NULL, ICON_NONE);
 }
 
@@ -331,6 +334,9 @@ void WM_OT_usd_import(wmOperatorType *ot)
   RNA_def_boolean(
       ot->srna, "import_normals", true, "normals", "When checked, import mesh normals.");
 
+  RNA_def_boolean(
+      ot->srna, "import_materials", true, "materials", "When checked, import materials.");
+
   RNA_def_float(
       ot->srna,
       "scale",
diff --git a/source/blender/io/usd/import/usd_reader_mesh.cc b/source/blender/io/usd/import/usd_reader_mesh.cc
index f6f321e3e94..368699f5b28 100644
--- a/source/blender/io/usd/import/usd_reader_mesh.cc
+++ b/source/blender/io/usd/import/usd_reader_mesh.cc
@@ -36,6 +36,8 @@
 #include "BKE_modifier.h"
 #include "BKE_object.h"
 
+#include <pxr/usd/usdShade/materialBindingAPI.h>
+
 #include <iostream>
 
 namespace {
@@ -317,6 +319,15 @@ static void process_normals(Mesh *mesh, const MeshSampleData &mesh_data)
   }
 }
 
+static void build_mtl_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
+{
+  Material *material = static_cast<Material *>(bmain->materials.first);
+
+  for (; material; material = static_cast<Material *>(material->id.next)) {
+    mat_map[material->id.name + 2] = material;
+  }
+}
+
 namespace blender::io::usd {
 
 UsdMeshReader::UsdMeshReader(const pxr::UsdPrim &prim, const USDImporterContext &context)
@@ -430,7 +441,179 @@ void UsdMeshReader::readObjectData(Main *bmain, double time)
     mesh->flag |= autosmooth;
   }
 
-  /* TODO(makowalski):  Read face sets and add modifier. */
+  if (this->context_.import_params.import_materials) {
+    assign_materials(bmain, mesh, time);
+  }
+
+  /* TODO(makowalski):  Add modifier. */
+}
+
+void UsdMeshReader::assign_materials(Main *bmain, Mesh *mesh, double time)
+{
+  if (!bmain || !mesh || !object_ || !mesh_) {
+    return;
+  }
+
+  /* Maps USD material names to material instances. */
+  std::map<std::string, pxr::UsdShadeMaterial> usd_mtl_map;
+
+  /* Each pair in the following vector represents a subset
+   * and the name of the material to which it's bound. */
+  std::vector<std::pair<pxr::UsdGeomSubset, std::string>> subset_mtls;
+
+  /* Find the geom subsets that have bound materials.
+   * We don't call pxr::UsdShadeMaterialBindingAPI::GetMaterialBindSubsets()
+   * because this function returns only those subsets that are in the 'materialBind'
+   * family, but, in practice, applications (like Houdini) might export subsets
+   * in different families that are bound to materials.
+   * TODO(makowalski): Reassess if the above is the best approach. */
+  const std::vector<pxr::UsdGeomSubset> face_subsets = pxr::UsdGeomSubset::GetAllGeomSubsets(
+      this->mesh_);
+
+  for (const pxr::UsdGeomSubset &sub : face_subsets) {
+    pxr::UsdShadeMaterialBindingAPI sub_bind_api(sub);
+    PXR_NS::UsdRelationship rel;
+    pxr::UsdShadeMaterial sub_bound_mtl = sub_bind_api.ComputeBoundMaterial(
+        PXR_NS::UsdShadeTokens->allPurpose, &rel);
+
+    /* Check if we have a bound material that was not inherited from another prim. */
+    if (sub_bound_mtl && rel.GetPrim() == sub.GetPrim()) {
+      pxr::UsdPrim mtl_prim = sub_bound_mtl.GetPrim();
+      if (mtl_prim) {
+        std::string mtl_name = sub_bound_mtl.GetPrim().GetName().GetString();
+        subset_mtls.push_back(std::make_pair(sub, mtl_name));
+        usd_mtl_map.insert(std::make_pair(mtl_name, sub_bound_mtl));
+      }
+    }
+  }
+
+  if (subset_mtls.empty()) {
+    /* No material subsets.  See if there is a material bound to the mesh. */
+
+    pxr::UsdShadeMaterialBindingAPI binding_api(this->mesh_.GetPrim());
+    pxr::UsdShadeMaterial bound_mtl = binding_api.ComputeBoundMaterial();
+
+    if (!bound_mtl || !bound_mtl.GetPrim()) {
+      return;
+    }
+
+    std::string mtl_name = bound_mtl.GetPrim().GetName().GetString();
+
+    if (!BKE_object_material_slot_add(bmain, object_)) {
+      std::cerr << "WARNING:  Couldn't add material slot for mesh prim " << this->prim_path_
+                << std::endl;
+      return;
+    }
+
+    Material *mtl = static_cast<Material *>(bmain->materials.first);
+    Material *blen_mtl = nullptr;
+
+    for (; mtl; mtl = static_cast<Material *>(mtl->id.next)) {
+      if (strcmp(mtl_name.c_str(), mtl->id.name + 2) == 0) {
+        /* Found an existing material with the same name. */
+        blen_mtl = mtl;
+        break;
+      }
+    }
+
+    if (!blen_mtl) {
+      blen_mtl = BKE_material_add(bmain, mtl_name.c_str());
+    }
+
+    if (!blen_mtl) {
+      std::cerr << "WARNING:  Couldn't add material " << mtl_name << " for mesh prim "
+                << this->prim_path_ << std::endl;
+    }
+
+    for (int p = 0; p < mesh->totpoly; ++p) {
+      mesh->mpoly[p].mat_nr = 0;
+    }
+
+    BKE_object_material_assign(bmain, object_, blen_mtl, 1, BKE_MAT_ASSIGN_OBDATA);
+  }
+  else {
+
+    /* Maps USD material names to material slot index. */
+    std::map<std::string, int> mtl_index_map;
+
+    /* Add material slots. */
+    std::map<std::string, pxr::UsdShadeMaterial>::const_iterator usd_mtl_iter =
+        usd_mtl_map.begin();
+
+    for (; usd_mtl_iter != usd_mtl_map.end(); ++usd_mtl_iter) {
+      if (!BKE_object_material_slot_add(bmain, object_)) {
+        std::cerr << "WARNING:  Couldn't add material slot for mesh prim " << this->prim_path_
+                  << std::endl;
+        return;
+      }
+    }
+
+    /* Create the Blender materials. */
+
+    /* Query the current materials. */
+    std::map<std::string, Material *> blen_mtl_map;
+    build_mtl_map(bmain, blen_mtl_map);
+
+    std::map<std::string, Material *>::iterator blen_mtl_iter = blen_mtl_map.begin();
+
+    usd_mtl_iter = usd_mtl_map.begin();
+    int idx = 0;
+
+    for (; usd_mtl_iter != usd_mtl_map.end(); ++usd_mtl_iter, ++idx) {
+      Material *blen_mtl = nullptr;
+
+      std::string mtl_name = usd_mtl_iter->first.c_str();
+
+      blen_mtl_iter = blen_mtl_map.find(mtl_name);
+
+      if (blen_mtl_iter != blen_mtl_map.end()) {
+        blen_mtl = blen_mtl_iter->second;
+      }
+      else {
+        blen_mtl = BKE_material_add(bmain, mtl_name.c_str());
+
+        if (blen_mtl) {
+          blen_mtl_map.insert(std::make_pair(mtl_name, blen_mtl));
+        }
+      }
+
+      if (!blen_mtl) {
+        std::cerr << "WARNING:  Couldn't add material " << mtl_name << " for mesh prim "
+                  << this->prim_path_ << std::endl;
+        return;
+      }
+
+      BKE_object_material_assign(bmain, object_, blen_mtl, idx + 1, BKE_MAT_ASSIGN_OBDATA);
+      mtl_index_map.insert(std::make_pair(usd_mtl_iter->first, idx));
+    }
+
+    /* Assign the material indices. */
+
+    for (const std::pair<pxr::UsdGeomSubset, std::string> &sub_mtl : subset_mtls) {
+
+      std::map<std::string, int>::const_iterator mtl_index_iter = mtl_index_map.find(
+          sub_mtl.second);
+
+      if (mtl_index_iter == mtl_index_map.end()) {
+        std::cerr << "WARNING:  Couldn't find material index." << std::endl;
+        return;
+      }
+
+      int mtl_idx = mtl_index_iter->second;
+      const pxr::UsdGeomSubset &sub = sub_mtl.first;
+
+      pxr::VtIntArray indices;
+      sub.GetIndicesAttr().Get(&indices, time);
+
+      for (int face_idx : indices) {
+        if (mtl_idx > mesh->totpoly) {
+          std::cerr << "WARNING:  Out of bounds material index." << std::endl;
+          return;
+        }
+        mesh->mpoly[face_idx].mat_nr = mtl_idx;
+      }
+    }
+  }
 }
 
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/import/usd_reader_mesh.h b/source/blender/io/usd/import/usd_reader_mesh.h
index 40bb7385765..3421e49eee7 100644
--- a/source/blender/io/usd/import/usd_reader_mesh.h
+++ b/source/blender/io/usd/import/usd_reader_mesh.h
@@ -41,6 +41,9 @@ class UsdMeshReader : public UsdObjectReader {
                          double time,
                          int read_flag,
                          const char **err_str) override;
+
+ protected:
+  void assign_materials(Main *bmain, Mesh *mesh, double time);
 };
 
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index c72952dd0bf..ebe798cb9b1 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -57,6 +57,7 @@ bool USD_export(struct bContext *C,
 struct USDImportParams {
   bool import_uvs;
   bool import_normals;
+  bool import_materials;
   float scale;
   bool debug;
 };



More information about the Bf-blender-cvs mailing list