Blender V5.0
io/usd/hydra/material.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "material.hh"
6#include "usd_private.hh"
7
8#include <Python.h>
9#include <unicodeobject.h>
10
11#include <pxr/base/tf/stringUtils.h>
12#include <pxr/imaging/hd/material.h>
13#include <pxr/imaging/hd/renderDelegate.h>
14#include <pxr/imaging/hd/tokens.h>
15#include <pxr/usdImaging/usdImaging/materialParamUtils.h>
16
17#ifdef WITH_MATERIALX
18# include <pxr/usd/usdMtlx/reader.h>
19# include <pxr/usd/usdMtlx/utils.h>
20#endif
21
23
25#include "image.hh"
26
29
30#ifdef WITH_MATERIALX
31
33#endif
34
35using namespace blender::io::usd;
36
37namespace blender::io::hydra {
38
40 const Material *material,
41 pxr::SdfPath const &prim_id)
42 : IdData(scene_delegate, &material->id, prim_id)
43{
44}
45
47{
48 ID_LOGN("");
49 double_sided = (((Material *)id)->blend_flag & MA_BL_CULL_BACKFACE) == 0;
50 material_network_map_ = pxr::VtValue();
51
52 /* Create temporary in memory stage. */
53 pxr::UsdStageRefPtr stage = pxr::UsdStage::CreateInMemory();
54 pxr::UsdTimeCode time = pxr::UsdTimeCode::Default();
55 auto get_time_code = [time]() { return time; };
56 pxr::SdfPath material_library_path("/_materials");
57 pxr::SdfPath material_path = material_library_path.AppendChild(
58 pxr::TfToken(prim_id.GetElementString()));
59
60 /* Create USD export content to reuse USD file export code. */
61 USDExportParams export_params;
62 export_params.relative_paths = false;
63 export_params.export_textures = false; /* Don't copy all textures, is slow. */
64 export_params.evaluation_mode = DEG_get_mode(scene_delegate_->depsgraph);
65
66 usd::USDExporterContext export_context{scene_delegate_->bmain,
67 scene_delegate_->depsgraph,
68 stage,
69 material_library_path,
70 get_time_code,
71 export_params,
74 /* Create USD material. */
75 pxr::UsdShadeMaterial usd_material;
76#ifdef WITH_MATERIALX
77 if (scene_delegate_->use_materialx) {
78 std::string material_name = pxr::TfMakeValidIdentifier(id->name);
79 blender::nodes::materialx::ExportParams materialx_export_params{
80 material_name, cache_or_get_image_file, "st", "UVMap"};
81 MaterialX::DocumentPtr doc = blender::nodes::materialx::export_to_materialx(
82 scene_delegate_->depsgraph, (Material *)id, materialx_export_params);
83 pxr::UsdMtlxRead(doc, stage);
84
85 /* Logging stage: creating lambda stage_str() to not call stage->ExportToString()
86 * if log won't be printed. */
87 auto stage_str = [&stage]() {
88 std::string str;
89 stage->ExportToString(&str);
90 return str;
91 };
92 ID_LOGN("Stage:\n%s", stage_str().c_str());
93
94 if (pxr::UsdPrim materials = stage->GetPrimAtPath(pxr::SdfPath("/MaterialX/Materials"))) {
95 pxr::UsdPrimSiblingRange children = materials.GetChildren();
96 if (!children.empty()) {
97 usd_material = pxr::UsdShadeMaterial(*children.begin());
98 }
99 }
100 }
101 else
102#endif
103 {
104 usd_material = usd::create_usd_material(
105 export_context, material_path, (Material *)id, "st", nullptr);
106 }
107
108 /* Convert USD material to Hydra material network map, adapted for render delegate. */
109 const pxr::HdRenderDelegate *render_delegate =
110 scene_delegate_->GetRenderIndex().GetRenderDelegate();
111 const pxr::TfTokenVector contextVector = render_delegate->GetMaterialRenderContexts();
112 pxr::TfTokenVector shaderSourceTypes = render_delegate->GetShaderSourceTypes();
113
114 pxr::HdMaterialNetworkMap network_map;
115
116 if (pxr::UsdShadeShader surface = usd_material.ComputeSurfaceSource(contextVector)) {
117 pxr::UsdImagingBuildHdMaterialNetworkFromTerminal(surface.GetPrim(),
118 pxr::HdMaterialTerminalTokens->surface,
119 shaderSourceTypes,
120 contextVector,
121 &network_map,
122 time);
123 }
124
125 material_network_map_ = pxr::VtValue(network_map);
126}
127
129{
130 ID_LOGN("");
131 scene_delegate_->GetRenderIndex().InsertSprim(
132 pxr::HdPrimTypeTokens->material, scene_delegate_, prim_id);
133}
134
136{
137 ID_LOG("");
138 scene_delegate_->GetRenderIndex().RemoveSprim(pxr::HdPrimTypeTokens->material, prim_id);
139}
140
142{
143 ID_LOGN("");
144 bool prev_double_sided = double_sided;
145 init();
146 scene_delegate_->GetRenderIndex().GetChangeTracker().MarkSprimDirty(prim_id,
147 pxr::HdMaterial::AllDirty);
148 if (prev_double_sided != double_sided) {
149 for (auto &obj_data : scene_delegate_->objects_.values()) {
150 MeshData *m_data = dynamic_cast<MeshData *>(obj_data.get());
151 if (m_data) {
152 m_data->update_double_sided(this);
153 }
154 }
155 scene_delegate_->instancer_data_->update_double_sided(this);
156 }
157}
158
159pxr::VtValue MaterialData::get_data(pxr::TfToken const & /*key*/) const
160{
161 return pxr::VtValue();
162}
163
165{
166 return material_network_map_;
167}
168
169pxr::HdCullStyle MaterialData::cull_style() const
170{
171 return double_sided ? pxr::HdCullStyle::HdCullStyleNothing : pxr::HdCullStyle::HdCullStyleBack;
172}
173
174} // namespace blender::io::hydra
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
@ MA_BL_CULL_BACKFACE
btAlignedObjectArray< btScalar > m_data
IdData(HydraSceneDelegate *scene_delegate, const ID *id, pxr::SdfPath const &prim_id)
Definition id.cc:9
pxr::SdfPath prim_id
Definition id.hh:36
HydraSceneDelegate * scene_delegate_
Definition id.hh:39
MaterialData(HydraSceneDelegate *scene_delegate, const Material *material, pxr::SdfPath const &prim_id)
pxr::VtValue get_data(pxr::TfToken const &key) const override
#define str(s)
#define ID_LOGN(msg,...)
Definition id.hh:55
#define ID_LOG(msg,...)
Definition id.hh:53
std::string cache_or_get_image_file(Main *bmain, Scene *scene, Image *image, ImageUser *iuser)
std::string image_cache_file_path()
pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_context, pxr::SdfPath usd_path, Material *material, const std::string &active_uvmap_name, ReportList *reports)
MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph, Material *material, const ExportParams &export_params)
enum eEvaluationMode evaluation_mode
Definition usd.hh:157