14#include <pxr/imaging/hd/sceneDelegate.h>
20 ((cyclesSurface,
"cycles:surface"))
21 ((cyclesDisplacement,
"cycles:displacement"))
22 ((cyclesVolume,
"cycles:volume"))
25 (UsdPrimvarReader_float)
26 (UsdPrimvarReader_float2)
27 (UsdPrimvarReader_float3)
28 (UsdPrimvarReader_float4)
29 (UsdPrimvarReader_int)
46 using ParamMap = std::unordered_map<TfToken, ustring, TfToken::HashFunctor>;
50 : _nodeType(
nodeType), _paramMap(std::move(paramMap))
61 VtValue * =
nullptr)
const
66 if (inputConnection) {
67 if (
name == CyclesMaterialTokens->a) {
70 if (
name == CyclesMaterialTokens->rgb) {
74 if (
name == CyclesMaterialTokens->r ||
name == CyclesMaterialTokens->g ||
75 name == CyclesMaterialTokens->b)
80 if (
name == CyclesMaterialTokens->result) {
98 const auto it = _paramMap.find(
name);
99 return it != _paramMap.end() ? it->second.string() :
name.GetString();
103 const ustring _nodeType;
113 VtValue *value)
const override
117 if (
name == CyclesMaterialTokens->wrapS ||
name == CyclesMaterialTokens->wrapT) {
118 const std::string valueString = VtValue::Cast<std::string>(*value).Get<std::string>();
121 if (valueString ==
"repeat") {
122 *value = VtValue(CyclesMaterialTokens->periodic);
136 const UsdToCyclesMapping UsdPreviewSurface = {
139 {TfToken(
"diffuseColor"), ustring(
"base_color")},
140 {TfToken(
"emissiveColor"), ustring(
"emission")},
141 {TfToken(
"specularColor"), ustring(
"specular")},
142 {TfToken(
"clearcoatRoughness"), ustring(
"coat_roughness")},
143 {TfToken(
"opacity"), ustring(
"alpha")},
148 const UsdToCyclesTexture UsdUVTexture = {
151 {CyclesMaterialTokens->st, ustring(
"vector")},
152 {CyclesMaterialTokens->wrapS, ustring(
"extension")},
153 {CyclesMaterialTokens->wrapT, ustring(
"extension")},
154 {TfToken(
"file"), ustring(
"filename")},
155 {TfToken(
"sourceColorSpace"), ustring(
"colorspace")},
157 const UsdToCyclesMapping UsdPrimvarReader = {
"attribute",
158 {{TfToken(
"varname"), ustring(
"attribute")}}};
161 const UsdToCyclesMapping *findUsd(
const TfToken &usdNodeType)
163 if (usdNodeType == CyclesMaterialTokens->UsdPreviewSurface) {
164 return &UsdPreviewSurface;
166 if (usdNodeType == CyclesMaterialTokens->UsdUVTexture) {
167 return &UsdUVTexture;
169 if (usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float ||
170 usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float2 ||
171 usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float3 ||
172 usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float4 ||
173 usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_int)
175 return &UsdPrimvarReader;
180 const UsdToCyclesMapping *findCycles(
const ustring & )
185TfStaticData<UsdToCycles> sUsdToCyles;
195 return DirtyBits::DirtyResource | DirtyBits::DirtyParams;
199 HdRenderParam *renderParam,
200 HdDirtyBits *dirtyBits)
202 if (*dirtyBits == DirtyBits::Clean) {
206 Initialize(renderParam);
210 const bool dirtyParams = (*dirtyBits & DirtyBits::DirtyParams);
211 const bool dirtyResource = (*dirtyBits & DirtyBits::DirtyResource);
214 const SdfPath &
id = GetId();
216 if (dirtyResource || dirtyParams) {
217 value = sceneDelegate->GetMaterialResource(
id);
219 const HdMaterialNetwork2 *network =
nullptr;
220 std::unique_ptr<HdMaterialNetwork2> networkConverted;
221 if (value.IsHolding<HdMaterialNetwork2>()) {
222 network = &value.UncheckedGet<HdMaterialNetwork2>();
224 else if (value.IsHolding<HdMaterialNetworkMap>()) {
225 const auto &networkOld = value.UncheckedGet<HdMaterialNetworkMap>();
228 if (!_nodes.empty() && !dirtyResource) {
229 for (
const auto &networkEntry : networkOld.map) {
230 UpdateParameters(networkEntry.second);
232 _shader->tag_modified();
235 networkConverted = std::make_unique<HdMaterialNetwork2>();
236#if PXR_VERSION >= 2205
237 *networkConverted = HdConvertToHdMaterialNetwork2(networkOld);
239 HdMaterialNetwork2ConvertFromHdMaterialNetworkMap(networkOld, networkConverted.get());
241 network = networkConverted.get();
245 TF_RUNTIME_ERROR(
"Could not get a HdMaterialNetwork2.");
249 if (!_nodes.empty() && !dirtyResource) {
250 UpdateParameters(*network);
251 _shader->tag_modified();
254 PopulateShaderGraph(*network);
259 if (_shader->is_modified()) {
260 _shader->tag_update(
lock.scene);
263 *dirtyBits = DirtyBits::Clean;
266void HdCyclesMaterial::UpdateParameters(NodeDesc &nodeDesc,
267 const std::map<TfToken, VtValue> ¶meters,
268 const SdfPath &nodePath)
270 for (
const auto ¶m : parameters) {
271 VtValue value = param.second;
275 const std::string inputName = inputMapping ?
277 param.first.GetString();
289 TF_WARN(
"Could not find parameter '%s' on node '%s' ('%s')",
290 param.first.GetText(),
292 nodeDesc.node->name.c_str());
300void HdCyclesMaterial::UpdateParameters(
const HdMaterialNetwork &network)
302 for (
const HdMaterialNode &nodeEntry : network.nodes) {
303 const SdfPath &nodePath = nodeEntry.path;
305 const auto nodeIt = _nodes.find(nodePath);
306 if (nodeIt == _nodes.end()) {
307 TF_RUNTIME_ERROR(
"Could not update parameters on missing node '%s'", nodePath.GetText());
311 UpdateParameters(nodeIt->second, nodeEntry.parameters, nodePath);
315void HdCyclesMaterial::UpdateParameters(
const HdMaterialNetwork2 &network)
317 for (
const auto &nodeEntry : network.nodes) {
318 const SdfPath &nodePath = nodeEntry.first;
320 const auto nodeIt = _nodes.find(nodePath);
321 if (nodeIt == _nodes.end()) {
322 TF_RUNTIME_ERROR(
"Could not update parameters on missing node '%s'", nodePath.GetText());
326 UpdateParameters(nodeIt->second, nodeEntry.second.parameters, nodePath);
330void HdCyclesMaterial::UpdateConnections(NodeDesc &nodeDesc,
331 const HdMaterialNode2 &matNode,
332 const SdfPath &nodePath,
335 for (
const auto &connection : matNode.inputConnections) {
336 const TfToken &dstSocketName = connection.first;
338 const UsdToCyclesMapping *inputMapping = nodeDesc.mapping;
339 const std::string inputName = inputMapping ?
341 dstSocketName.GetString();
344 ShaderInput *
input =
nullptr;
345 for (ShaderInput *
in : nodeDesc.node->inputs) {
353 TF_WARN(
"Ignoring connection on '%s.%s', input '%s' was not found",
355 dstSocketName.GetText(),
356 dstSocketName.GetText());
361 const auto &connectedNodes = connection.second;
362 if (connectedNodes.empty()) {
368 if (connectedNodes.size() > 1) {
370 "Ignoring multiple connections to '%s.%s'", nodePath.GetText(), dstSocketName.GetText());
373 const SdfPath &upstreamNodePath = connectedNodes.front().upstreamNode;
374 const TfToken &upstreamOutputName = connectedNodes.front().upstreamOutputName;
376 const auto srcNodeIt = _nodes.find(upstreamNodePath);
377 if (srcNodeIt == _nodes.end()) {
378 TF_WARN(
"Ignoring connection from '%s.%s' to '%s.%s', node '%s' was not found",
379 upstreamNodePath.GetText(),
380 upstreamOutputName.GetText(),
382 dstSocketName.GetText(),
383 upstreamNodePath.GetText());
387 const UsdToCyclesMapping *outputMapping = srcNodeIt->second.mapping;
388 const std::string outputName = outputMapping ?
390 upstreamOutputName.GetString();
392 ShaderOutput *
output =
nullptr;
393 for (ShaderOutput *
out : srcNodeIt->second.node->outputs) {
401 TF_WARN(
"Ignoring connection from '%s.%s' to '%s.%s', output '%s' was not found",
402 upstreamNodePath.GetText(),
403 upstreamOutputName.GetText(),
405 dstSocketName.GetText(),
406 upstreamOutputName.GetText());
414void HdCyclesMaterial::PopulateShaderGraph(
const HdMaterialNetwork2 &networkMap)
418 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
421 for (
const auto &nodeEntry : networkMap.nodes) {
422 NodeDesc nodeDesc = {};
423 const SdfPath &nodePath = nodeEntry.first;
425 const auto nodeIt = _nodes.find(nodePath);
427 if (nodeIt != _nodes.end()) {
428 nodeDesc = nodeIt->second;
432 const std::string &nodeTypeId = nodeEntry.second.nodeTypeId.GetString();
434 ustring cyclesType(nodeTypeId);
436 if (nodeTypeId.rfind(
"cycles", 0) == 0) {
437 cyclesType = nodeTypeId.substr(7);
438 nodeDesc.mapping = sUsdToCyles->findCycles(cyclesType);
442 nodeDesc.mapping = sUsdToCyles->findUsd(nodeEntry.second.nodeTypeId);
443 if (nodeDesc.mapping) {
444 cyclesType = nodeDesc.mapping->nodeType();
450 nodeDesc.node = graph->create_node(nodeType);
451 _nodes.emplace(nodePath, nodeDesc);
454 TF_RUNTIME_ERROR(
"Could not create node '%s'", nodePath.GetText());
459 UpdateParameters(nodeDesc, nodeEntry.second.parameters, nodePath);
464 for (
const auto &nodeEntry : networkMap.nodes) {
465 const SdfPath &nodePath = nodeEntry.first;
467 const auto nodeIt = _nodes.find(nodePath);
468 if (nodeIt == _nodes.end()) {
469 TF_RUNTIME_ERROR(
"Could not find node '%s' to connect", nodePath.GetText());
473 UpdateConnections(nodeIt->second, nodeEntry.second, nodePath, graph.get());
477 for (
const auto &terminalEntry : networkMap.terminals) {
478 const TfToken &terminalName = terminalEntry.first;
479 const HdMaterialConnection2 &connection = terminalEntry.second;
481 const auto nodeIt = _nodes.find(connection.upstreamNode);
482 if (nodeIt == _nodes.end()) {
483 TF_RUNTIME_ERROR(
"Could not find terminal node '%s'", connection.upstreamNode.GetText());
487 ShaderNode *
const node = nodeIt->second.node;
489 const char *inputName =
nullptr;
490 const char *outputName =
nullptr;
491 if (terminalName == HdMaterialTerminalTokens->surface ||
492 terminalName == CyclesMaterialTokens->cyclesSurface)
494 inputName =
"Surface";
496 if (node->
type->
name ==
"add_closure" || node->
type->
name ==
"mix_closure") {
497 outputName =
"Closure";
499 else if (node->
type->
name ==
"emission") {
500 outputName =
"Emission";
506 else if (terminalName == HdMaterialTerminalTokens->displacement ||
507 terminalName == CyclesMaterialTokens->cyclesDisplacement)
509 inputName = outputName =
"Displacement";
511 else if (terminalName == HdMaterialTerminalTokens->volume ||
512 terminalName == CyclesMaterialTokens->cyclesVolume)
514 inputName = outputName =
"Volume";
517 if (!connection.upstreamOutputName.IsEmpty()) {
518 outputName = connection.upstreamOutputName.GetText();
521 ShaderInput *
const input = inputName ? graph->output()->input(inputName) :
nullptr;
523 TF_RUNTIME_ERROR(
"Could not find terminal input '%s.%s'",
524 connection.upstreamNode.GetText(),
525 inputName ? inputName :
"<null>");
529 ShaderOutput *
const output = outputName ? node->
output(outputName) :
nullptr;
531 TF_RUNTIME_ERROR(
"Could not find terminal output '%s.%s'",
532 connection.upstreamNode.GetText(),
533 outputName ? outputName :
"<null>");
542 const ustring instanceId(HdAovTokens->instanceId.GetString());
544 OutputAOVNode *aovNode = graph->create_node<OutputAOVNode>();
545 aovNode->set_name(instanceId);
547 AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
548 instanceIdNode->set_attribute(instanceId);
550 graph->connect(instanceIdNode->
output(
"Fac"), aovNode->
input(
"Value"));
553 _shader->set_graph(std::move(graph));
563 const bool keep_nodes =
static_cast<const HdCyclesSession *
>(renderParam)->keep_nodes;
568 lock.scene->delete_node(_shader);
573void HdCyclesMaterial::Initialize(HdRenderParam *renderParam)
579 const SceneLock
lock(renderParam);
PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override
void Finalize(PXR_NS::HdRenderParam *renderParam) override
HdCyclesMaterial(const PXR_NS::SdfPath &sprimId)
~HdCyclesMaterial() override
void Sync(PXR_NS::HdSceneDelegate *sceneDelegate, PXR_NS::HdRenderParam *renderParam, PXR_NS::HdDirtyBits *dirtyBits) override
void connect(ShaderOutput *from, ShaderInput *to)
ShaderInput * input(const char *name)
ShaderOutput * output(const char *name)
UsdToCyclesMapping(const char *nodeType, ParamMap paramMap)
virtual std::string parameterName(const TfToken &name, const ShaderInput *inputConnection, VtValue *=nullptr) const
UsdToCyclesMapping(const char *nodeType, ParamMap paramMap)
std::string parameterName(const TfToken &name, const ShaderInput *inputConnection, VtValue *value) const override
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
HDCYCLES_NAMESPACE_OPEN_SCOPE TF_DEFINE_PRIVATE_TOKENS(CyclesMaterialTokens,((cyclesSurface, "cycles:surface"))((cyclesDisplacement, "cycles:displacement"))((cyclesVolume, "cycles:volume"))(UsdPreviewSurface)(UsdUVTexture)(UsdPrimvarReader_float)(UsdPrimvarReader_float2)(UsdPrimvarReader_float3)(UsdPrimvarReader_float4)(UsdPrimvarReader_int)(UsdTransform2d)(a)(rgb)(r)(g)(b)(result)(st)(wrapS)(wrapT)(periodic))
void SetNodeValue(Node *node, const SocketType &socket, const VtValue &value)
bool string_iequals(const string &a, const string &b)
static const NodeType * find(ustring name)