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 *value =
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 std::string valueString = VtValue::Cast<std::string>(*value).Get<std::string>();
121 if (valueString ==
"repeat") {
122 *value = VtValue(CyclesMaterialTokens->periodic);
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")},
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")},
158 {{TfToken(
"varname"), ustring(
"attribute")}}};
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;
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);
220 const HdMaterialNetwork2 *network =
nullptr;
221 std::unique_ptr<HdMaterialNetwork2> networkConverted;
222 if (value.IsHolding<HdMaterialNetwork2>()) {
223 network = &value.UncheckedGet<HdMaterialNetwork2>();
225 else if (value.IsHolding<HdMaterialNetworkMap>()) {
226 const auto &networkOld = value.UncheckedGet<HdMaterialNetworkMap>();
229 if (!_nodes.empty() && !dirtyResource) {
230 for (
const auto &networkEntry : networkOld.map) {
231 UpdateParameters(networkEntry.second);
233 _shader->tag_modified();
236 networkConverted = std::make_unique<HdMaterialNetwork2>();
237# if PXR_VERSION >= 2205
238 *networkConverted = HdConvertToHdMaterialNetwork2(networkOld);
240 HdMaterialNetwork2ConvertFromHdMaterialNetworkMap(networkOld, networkConverted.get());
242 network = networkConverted.get();
246 TF_RUNTIME_ERROR(
"Could not get a HdMaterialNetwork2.");
250 if (!_nodes.empty() && !dirtyResource) {
251 UpdateParameters(*network);
252 _shader->tag_modified();
255 PopulateShaderGraph(*network);
261 if (_shader->is_modified()) {
262 _shader->tag_update(
lock.scene);
265 *dirtyBits = DirtyBits::Clean;
268void HdCyclesMaterial::UpdateParameters(NodeDesc &nodeDesc,
270 const SdfPath &nodePath)
273 VtValue value = param.second;
277 const std::string inputName = inputMapping ?
279 param.first.GetString();
283 for (
const SocketType &socket : nodeDesc.node->type->inputs) {
284 if (
string_iequals(socket.name.string(), inputName) || socket.ui_name == inputName) {
291 TF_WARN(
"Could not find parameter '%s' on node '%s' ('%s')",
292 param.first.GetText(),
294 nodeDesc.node->name.c_str());
302void HdCyclesMaterial::UpdateParameters(
const HdMaterialNetwork &network)
304 for (
const HdMaterialNode &nodeEntry : network.nodes) {
305 const SdfPath &nodePath = nodeEntry.path;
307 const auto nodeIt = _nodes.find(nodePath);
308 if (nodeIt == _nodes.end()) {
309 TF_RUNTIME_ERROR(
"Could not update parameters on missing node '%s'", nodePath.GetText());
313 UpdateParameters(nodeIt->second, nodeEntry.parameters, nodePath);
317void HdCyclesMaterial::UpdateParameters(
const HdMaterialNetwork2 &network)
319 for (
const auto &nodeEntry : network.nodes) {
320 const SdfPath &nodePath = nodeEntry.first;
322 const auto nodeIt = _nodes.find(nodePath);
323 if (nodeIt == _nodes.end()) {
324 TF_RUNTIME_ERROR(
"Could not update parameters on missing node '%s'", nodePath.GetText());
328 UpdateParameters(nodeIt->second, nodeEntry.second.parameters, nodePath);
332void HdCyclesMaterial::UpdateConnections(NodeDesc &nodeDesc,
333 const HdMaterialNode2 &matNode,
334 const SdfPath &nodePath,
337 for (
const auto &connection : matNode.inputConnections) {
338 const TfToken &dstSocketName = connection.first;
341 const std::string inputName = inputMapping ?
343 dstSocketName.GetString();
355 TF_WARN(
"Ignoring connection on '%s.%s', input '%s' was not found",
357 dstSocketName.GetText(),
358 dstSocketName.GetText());
363 const auto &connectedNodes = connection.second;
364 if (connectedNodes.empty()) {
370 if (connectedNodes.size() > 1) {
372 "Ignoring multiple connections to '%s.%s'", nodePath.GetText(), dstSocketName.GetText());
375 const SdfPath &upstreamNodePath = connectedNodes.front().upstreamNode;
376 const TfToken &upstreamOutputName = connectedNodes.front().upstreamOutputName;
378 const auto srcNodeIt = _nodes.find(upstreamNodePath);
379 if (srcNodeIt == _nodes.end()) {
380 TF_WARN(
"Ignoring connection from '%s.%s' to '%s.%s', node '%s' was not found",
381 upstreamNodePath.GetText(),
382 upstreamOutputName.GetText(),
384 dstSocketName.GetText(),
385 upstreamNodePath.GetText());
390 const std::string outputName = outputMapping ?
392 upstreamOutputName.GetString();
395 for (
ShaderOutput *out : srcNodeIt->second.node->outputs) {
403 TF_WARN(
"Ignoring connection from '%s.%s' to '%s.%s', output '%s' was not found",
404 upstreamNodePath.GetText(),
405 upstreamOutputName.GetText(),
407 dstSocketName.GetText(),
408 upstreamOutputName.GetText());
412 shaderGraph->
connect(output, input);
416void HdCyclesMaterial::PopulateShaderGraph(
const HdMaterialNetwork2 &networkMap)
423 for (
const auto &nodeEntry : networkMap.nodes) {
424 NodeDesc nodeDesc = {};
425 const SdfPath &nodePath = nodeEntry.first;
427 const auto nodeIt = _nodes.find(nodePath);
429 if (nodeIt != _nodes.end()) {
430 nodeDesc = nodeIt->second;
434 const std::string &nodeTypeId = nodeEntry.second.nodeTypeId.GetString();
436 ustring cyclesType(nodeTypeId);
438 if (nodeTypeId.rfind(
"cycles", 0) == 0) {
439 cyclesType = nodeTypeId.substr(7);
440 nodeDesc.mapping = sUsdToCyles->findCycles(cyclesType);
444 nodeDesc.mapping = sUsdToCyles->findUsd(nodeEntry.second.nodeTypeId);
445 if (nodeDesc.mapping) {
446 cyclesType = nodeDesc.mapping->nodeType();
452 nodeDesc.node =
static_cast<ShaderNode *
>(nodeType->create(nodeType));
455 graph->add(nodeDesc.node);
457 _nodes.emplace(nodePath, nodeDesc);
460 TF_RUNTIME_ERROR(
"Could not create node '%s'", nodePath.GetText());
465 UpdateParameters(nodeDesc, nodeEntry.second.parameters, nodePath);
470 for (
const auto &nodeEntry : networkMap.nodes) {
471 const SdfPath &nodePath = nodeEntry.first;
473 const auto nodeIt = _nodes.find(nodePath);
474 if (nodeIt == _nodes.end()) {
475 TF_RUNTIME_ERROR(
"Could not find node '%s' to connect", nodePath.GetText());
479 UpdateConnections(nodeIt->second, nodeEntry.second, nodePath, graph);
483 for (
const auto &terminalEntry : networkMap.terminals) {
484 const TfToken &terminalName = terminalEntry.first;
485 const HdMaterialConnection2 &connection = terminalEntry.second;
487 const auto nodeIt = _nodes.find(connection.upstreamNode);
488 if (nodeIt == _nodes.end()) {
489 TF_RUNTIME_ERROR(
"Could not find terminal node '%s'", connection.upstreamNode.GetText());
495 const char *inputName =
nullptr;
496 const char *outputName =
nullptr;
497 if (terminalName == HdMaterialTerminalTokens->surface ||
498 terminalName == CyclesMaterialTokens->cyclesSurface)
500 inputName =
"Surface";
502 if (node->type->name ==
"add_closure" || node->type->name ==
"mix_closure") {
503 outputName =
"Closure";
505 else if (node->type->name ==
"emission") {
506 outputName =
"Emission";
512 else if (terminalName == HdMaterialTerminalTokens->displacement ||
513 terminalName == CyclesMaterialTokens->cyclesDisplacement)
515 inputName = outputName =
"Displacement";
517 else if (terminalName == HdMaterialTerminalTokens->volume ||
518 terminalName == CyclesMaterialTokens->cyclesVolume)
520 inputName = outputName =
"Volume";
523 if (!connection.upstreamOutputName.IsEmpty()) {
524 outputName = connection.upstreamOutputName.GetText();
527 ShaderInput *
const input = inputName ? graph->output()->input(inputName) :
nullptr;
529 TF_RUNTIME_ERROR(
"Could not find terminal input '%s.%s'",
530 connection.upstreamNode.GetText(),
531 inputName ? inputName :
"<null>");
535 ShaderOutput *
const output = outputName ? node->output(outputName) :
nullptr;
537 TF_RUNTIME_ERROR(
"Could not find terminal output '%s.%s'",
538 connection.upstreamNode.GetText(),
539 outputName ? outputName :
"<null>");
543 graph->connect(output, input);
548 const ustring instanceId(HdAovTokens->instanceId.GetString());
551 aovNode->set_name(instanceId);
555 instanceIdNode->set_attribute(instanceId);
556 graph->add(instanceIdNode);
558 graph->connect(instanceIdNode->
output(
"Fac"), aovNode->
input(
"Value"));
561 _shader->set_graph(graph);
571 const bool keep_nodes =
static_cast<const HdCyclesSession *
>(renderParam)->keep_nodes;
576 lock.scene->delete_node(_shader);
581void HdCyclesMaterial::Initialize(HdRenderParam *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)
virtual std::string parameterName(const TfToken &name, const ShaderInput *inputConnection, VtValue *value=nullptr) const
UsdToCyclesMapping(const char *nodeType, ParamMap paramMap)
std::string parameterName(const TfToken &name, const ShaderInput *inputConnection, VtValue *value) const override
local_group_size(16, 16) .push_constant(Type b
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
double parameters[NUM_PARAMETERS]
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)
void set_owner(const NodeOwner *owner_)