Commit: 60090d61eadb7daadf10f12c3387b2c118499736 Author: Sybren A. Stüvel Date: Thu Jun 27 16:45:36 2019 +0200 Branches: sybren-usd https://developer.blender.org/rB60090d61eadb7daadf10f12c3387b2c118499736
USD: support for simple preview materials Very simple versions of the materials are now exported, using only the viewport diffuse RGB, metallic, and roughness. When there are multiple materials, the mesh faces are stored as geometry subset and each material is assigned to the appropriate subset. If there is only one material this is skipped. The first material if any) is always applied to the mesh itself (regardless of the existence of geometry subsets), because the Hydra viewport doesn't support materials on subsets. See https://github.com/PixarAnimationStudios/USD/issues/542 for more info. Note that the geometry subsets are not yet time-sampled, so it will break when an animated mesh changes topology. =================================================================== M source/blender/usd/intern/abstract_hierarchy_iterator.h M source/blender/usd/intern/usd_hierarchy_iterator.h M source/blender/usd/intern/usd_writer_abstract.cc M source/blender/usd/intern/usd_writer_abstract.h M source/blender/usd/intern/usd_writer_mesh.cc M source/blender/usd/intern/usd_writer_mesh.h =================================================================== diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.h b/source/blender/usd/intern/abstract_hierarchy_iterator.h index 4d39778b0bd..fa5661adb3d 100644 --- a/source/blender/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/usd/intern/abstract_hierarchy_iterator.h @@ -70,6 +70,8 @@ class AbstractHierarchyIterator { const WriterMap &writer_map() const; void release_writers(); + virtual std::string get_id_name(const ID *id) const = 0; + private: void construct_export_graph(); void visit_object(Object *object, Object *export_parent, bool weak_export); @@ -96,7 +98,6 @@ class AbstractHierarchyIterator { virtual void delete_object_writer(AbstractHierarchyWriter *writer) = 0; - virtual std::string get_id_name(const ID *id) const = 0; virtual std::string path_concatenate(const std::string &parent_path, const std::string &child_path) const; }; diff --git a/source/blender/usd/intern/usd_hierarchy_iterator.h b/source/blender/usd/intern/usd_hierarchy_iterator.h index c52bdec6471..7c4df467da3 100644 --- a/source/blender/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/usd/intern/usd_hierarchy_iterator.h @@ -28,13 +28,14 @@ class USDHierarchyIterator : public AbstractHierarchyIterator { void set_export_frame(float frame_nr); const pxr::UsdTimeCode &get_export_time_code() const; + virtual std::string get_id_name(const ID *const id) const override; + protected: virtual bool should_export_object(const Object *object) const override; virtual AbstractHierarchyWriter *create_xform_writer(const HierarchyContext &context) override; virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext &context) override; - virtual std::string get_id_name(const ID *const id) const override; virtual void delete_object_writer(AbstractHierarchyWriter *writer) override; }; diff --git a/source/blender/usd/intern/usd_writer_abstract.cc b/source/blender/usd/intern/usd_writer_abstract.cc index 59e3a34d6ef..86143b1d035 100644 --- a/source/blender/usd/intern/usd_writer_abstract.cc +++ b/source/blender/usd/intern/usd_writer_abstract.cc @@ -94,3 +94,33 @@ const pxr::SdfPath &USDAbstractWriter::usd_path() const { return usd_path_; } + +pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(Material *material) +{ + static pxr::SdfPath material_library_path("/_materials"); + + // Construct the material. + pxr::TfToken material_name(hierarchy_iterator->get_id_name(&material->id)); + pxr::SdfPath usd_path = material_library_path.AppendChild(material_name); + pxr::UsdShadeMaterial usd_material = pxr::UsdShadeMaterial::Get(stage, usd_path); + if (usd_material) { + return usd_material; + } + usd_material = pxr::UsdShadeMaterial::Define(stage, usd_path); + + // Construct the shader. + pxr::SdfPath shader_path = usd_path.AppendChild(pxr::TfToken("previewShader")); + pxr::UsdShadeShader shader = pxr::UsdShadeShader::Define(stage, shader_path); + shader.CreateIdAttr(pxr::VtValue(pxr::TfToken("UsdPreviewSurface"))); + shader.CreateInput(pxr::TfToken("diffuseColor"), pxr::SdfValueTypeNames->Color3f) + .Set(pxr::GfVec3f(material->r, material->g, material->b)); + shader.CreateInput(pxr::TfToken("roughness"), pxr::SdfValueTypeNames->Float) + .Set(material->roughness); + shader.CreateInput(pxr::TfToken("metallic"), pxr::SdfValueTypeNames->Float) + .Set(material->metallic); + + // Connect the shader and the material together. + usd_material.CreateSurfaceOutput().ConnectToSource(shader, pxr::TfToken("surface")); + + return usd_material; +} diff --git a/source/blender/usd/intern/usd_writer_abstract.h b/source/blender/usd/intern/usd_writer_abstract.h index 2a67f878737..3e2feb3faf9 100644 --- a/source/blender/usd/intern/usd_writer_abstract.h +++ b/source/blender/usd/intern/usd_writer_abstract.h @@ -4,14 +4,19 @@ #include "usd_exporter_context.h" #include "abstract_hierarchy_iterator.h" -#include "DEG_depsgraph_query.h" - #include <pxr/usd/sdf/path.h> #include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdShade/material.h> #include <vector> +extern "C" { +#include "DEG_depsgraph_query.h" +#include "DNA_material_types.h" +} + struct Main; +struct Material; struct Object; class USDAbstractWriter : public AbstractHierarchyWriter { @@ -40,6 +45,8 @@ class USDAbstractWriter : public AbstractHierarchyWriter { virtual void do_write(HierarchyContext &context) = 0; virtual bool check_is_animated(const HierarchyContext &context) const; pxr::UsdTimeCode get_export_time_code() const; + + pxr::UsdShadeMaterial ensure_usd_material(Material *material); }; #endif /* __USD__USD_WRITER_ABSTRACT_H__ */ diff --git a/source/blender/usd/intern/usd_writer_mesh.cc b/source/blender/usd/intern/usd_writer_mesh.cc index 3ab72fbf723..42e46d9f934 100644 --- a/source/blender/usd/intern/usd_writer_mesh.cc +++ b/source/blender/usd/intern/usd_writer_mesh.cc @@ -2,10 +2,13 @@ #include "usd_hierarchy_iterator.h" #include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdShade/material.h> +#include <pxr/usd/usdShade/materialBindingAPI.h> extern "C" { #include "BKE_anim.h" #include "BKE_library.h" +#include "BKE_material.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -29,7 +32,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context) } try { - write_mesh(mesh); + write_mesh(context, mesh); if (needsfree) { free_export_mesh(mesh); @@ -48,7 +51,7 @@ void USDGenericMeshWriter::free_export_mesh(struct Mesh *mesh) BKE_id_free(NULL, mesh); } -void USDGenericMeshWriter::write_mesh(struct Mesh *mesh) +void USDGenericMeshWriter::write_mesh(HierarchyContext &context, struct Mesh *mesh) { pxr::UsdTimeCode timecode = get_export_time_code(); // printf("USD-\033[32mexporting\033[0m mesh %s → %s mesh = %p\n", @@ -77,15 +80,54 @@ void USDGenericMeshWriter::write_mesh(struct Mesh *mesh) MLoop *mloop = mesh->mloop; MPoly *mpoly = mesh->mpoly; + std::map<short, pxr::VtIntArray> face_groups; for (int i = 0; i < mesh->totpoly; ++i, ++mpoly) { MLoop *loop = mloop + mpoly->loopstart; usd_face_vertex_counts.push_back(mpoly->totloop); for (int j = 0; j < mpoly->totloop; ++j, ++loop) { usd_face_indices.push_back(loop->v); } + + face_groups[mpoly->mat_nr].push_back(i); } usd_mesh.CreateFaceVertexCountsAttr().Set(usd_face_vertex_counts, timecode); usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_face_indices, timecode); + + // TODO(Sybren): figure out what happens when the face groups change. + if (frame_has_been_written_) { + return; + } + + // Define a geometry subset per material. + bool mesh_material_bound = false; + for (auto face_group_iter : face_groups) { + short material_number = face_group_iter.first; + const pxr::VtIntArray &face_indices = face_group_iter.second; + + Material *material = give_current_material(context.object, material_number + 1); + if (material == nullptr) { + continue; + } + + pxr::UsdShadeMaterial usd_material = ensure_usd_material(material); + pxr::TfToken material_name = usd_material.GetPath().GetNameToken(); + + if (face_groups.size() > 1) { + // Only bother with writing face groups if the object has multiple materials. + pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(usd_mesh); + pxr::UsdGeomSubset usd_face_subset = api.CreateMaterialBindSubset(material_name, + face_indices); + usd_material.Bind(usd_face_subset.GetPrim()); + } + + /* Binding a material to a geometry subset isn't supported by the Hydra GL viewport yet, which + * is why we also bind the first material to the entire mesh. See + * https://github.com/PixarAnimationStudios/USD/issues/542 for more info. */ + if (!mesh_material_bound) { + usd_material.Bind(usd_mesh.GetPrim()); + mesh_material_bound = true; + } + } } USDMeshWriter::USDMeshWriter(const USDExporterContext &ctx) : USDGenericMeshWriter(ctx) diff --git a/source/blender/usd/intern/usd_writer_mesh.h b/source/blender/usd/intern/usd_writer_mesh.h index fc7138cabd9..001a09a1a88 100644 --- a/source/blender/usd/intern/usd_writer_mesh.h +++ b/source/blender/usd/intern/usd_writer_mesh.h @@ -15,7 +15,7 @@ class USDGenericMeshWriter : public USDAbstractWriter { virtual void free_export_mesh(Mesh *mesh); private: - void write_mesh(Mesh *mesh); + void write_mesh(HierarchyContext &context, Mesh *mesh); }; class USDMeshWriter : public USDGenericMeshWriter { _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs