Skip to content

Commit

Permalink
Imagers in the delegate and the reader (#1317)
Browse files Browse the repository at this point in the history
* Imagers (HTOA-1915)

* imagers v2

* Updated output terminal name from translator

* Read imager graphs in the reader

* Revert imager only wip

Co-authored-by: Julian Hodgson <julian.hodgson@autodesk.com>
  • Loading branch information
jhodgson and Julian Hodgson authored Oct 7, 2022
1 parent cb852c3 commit 1e2a2d3
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 36 deletions.
1 change: 1 addition & 0 deletions common/constant_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ ASTR(ignore_sss);
ASTR(ignore_subdivision);
ASTR(ignore_textures);
ASTR(image);
ASTR(imager);
ASTR(in);
ASTR(indexed);
ASTR(indirect_sample_clamp);
Expand Down
16 changes: 14 additions & 2 deletions ndr/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,10 @@ void _ReadArnoldShaderDef(UsdPrim& prim, const AtNodeEntry* nodeEntry)
if (conversion != nullptr) {
prim.CreateAttribute(_tokens->output, conversion->type, false);
}
} else if (AiNodeEntryGetType(nodeEntry) == AI_NODE_DRIVER) {
// create an output type for imagers
prim.CreateAttribute(_tokens->output, SdfValueTypeNames->String, false);
}

auto paramIter = AiNodeEntryGetParamIterator(nodeEntry);

while (!AiParamIteratorFinished(paramIter)) {
Expand Down Expand Up @@ -419,10 +421,20 @@ UsdStageRefPtr NdrArnoldGetShaderDefs()
#endif
}

auto* nodeIter = AiUniverseGetNodeEntryIterator(AI_NODE_SHADER);
auto* nodeIter = AiUniverseGetNodeEntryIterator(AI_NODE_SHADER | AI_NODE_DRIVER);

while (!AiNodeEntryIteratorFinished(nodeIter)) {

// filter out drivers that are not imagers
auto* nodeEntry = AiNodeEntryIteratorGetNext(nodeIter);
static const AtString s_subtype("subtype");
AtString subtype;
if ((AiNodeEntryGetType(nodeEntry) == AI_NODE_DRIVER))
{
if (!AiMetaDataGetStr(nodeEntry, AtString(), s_subtype, &subtype) || strcmp(subtype.c_str(), "imager"))
continue;
}

auto prim = stage->DefinePrim(SdfPath(TfStringPrintf("/%s", AiNodeEntryGetName(nodeEntry))));
_ReadArnoldShaderDef(prim, nodeEntry);
}
Expand Down
57 changes: 31 additions & 26 deletions render_delegate/node_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,32 +572,37 @@ AtNode* HdArnoldNodeGraph::ReadMaterialNetwork(const HdMaterialNetwork& network)
continue;
}

// Arnold nodes can only have one output... but you can connect to sub components of them.
// USD doesn't yet have component connections / swizzling, but it's nodes can have multiple
// outputs to which you can connect.
// Sometimes, the output parameter name effectively acts like a channel connection (ie,
// UsdUVTexture.outputs:r), so check for this.
bool useInputName = false;
if (relationship.inputName.size() == 1) {
const auto* inputNodeEntry = AiNodeGetNodeEntry(inputNode);
auto inputType = AiNodeEntryGetOutputType(inputNodeEntry);
if (relationship.inputName == _tokens->x || relationship.inputName == _tokens->y) {
useInputName = (inputType == AI_TYPE_VECTOR || inputType == AI_TYPE_VECTOR2);
} else if (relationship.inputName == _tokens->z) {
useInputName = (inputType == AI_TYPE_VECTOR);
} else if (
relationship.inputName == _tokens->r || relationship.inputName == _tokens->g ||
relationship.inputName == _tokens->b) {
useInputName = (inputType == AI_TYPE_RGB || inputType == AI_TYPE_RGBA);
} else if (relationship.inputName == _tokens->a) {
useInputName = (inputType == AI_TYPE_RGBA);
}
}
if (useInputName) {
AiNodeLinkOutput(
inputNode, relationship.inputName.GetText(), outputNode, outputAttr.c_str());
if (AiNodeEntryGetType(AiNodeGetNodeEntry(inputNode)) == AI_NODE_DRIVER) {
// imagers are chained with the input parameter
AiNodeSetPtr(outputNode, str::input, inputNode);
} else {
AiNodeLink(inputNode, outputAttr.c_str(), outputNode);
// Arnold shader nodes can only have one output... but you can connect to sub components of them.
// USD doesn't yet have component connections / swizzling, but it's nodes can have multiple
// outputs to which you can connect.
// Sometimes, the output parameter name effectively acts like a channel connection (ie,
// UsdUVTexture.outputs:r), so check for this.
bool useInputName = false;
if (relationship.inputName.size() == 1) {
const auto *inputNodeEntry = AiNodeGetNodeEntry(inputNode);
auto inputType = AiNodeEntryGetOutputType(inputNodeEntry);
if (relationship.inputName == _tokens->x || relationship.inputName == _tokens->y) {
useInputName = (inputType == AI_TYPE_VECTOR || inputType == AI_TYPE_VECTOR2);
} else if (relationship.inputName == _tokens->z) {
useInputName = (inputType == AI_TYPE_VECTOR);
} else if (
relationship.inputName == _tokens->r || relationship.inputName == _tokens->g ||
relationship.inputName == _tokens->b) {
useInputName = (inputType == AI_TYPE_RGB || inputType == AI_TYPE_RGBA);
} else if (relationship.inputName == _tokens->a) {
useInputName = (inputType == AI_TYPE_RGBA);
}
}
if (useInputName) {
AiNodeLinkOutput(
inputNode, relationship.inputName.GetText(), outputNode, outputAttr.c_str());
} else {
AiNodeLink(inputNode, outputAttr.c_str(), outputNode);
}
}
}

Expand Down Expand Up @@ -671,7 +676,7 @@ AtNode* HdArnoldNodeGraph::ReadMaterialNode(const HdMaterialNode& node)
oslSource = resourceNodeIt->second->node;

if (oslSource == nullptr) {
oslSource = AiNode(_renderDelegate->GetUniverse(), str::osl, resourceNodeName.c_str());
oslSource = AiNode(_renderDelegate->GetUniverse(), str::osl, AtString(resourceNodeName.c_str()));
AiNodeSetStr(oslSource, str::code, tx_code);
auto resourceNodeData = NodeDataPtr(new NodeData(oslSource, true));
_nodes.emplace(resourceNodePath, resourceNodeData);
Expand Down
13 changes: 13 additions & 0 deletions render_delegate/render_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ const SupportedRenderSettings& _GetSupportedRenderSettings()
{str::t_background, {"Path to the background node graph.", std::string{}}},
{str::t_atmosphere, {"Path to the atmosphere node graph.", std::string{}}},
{str::t_aov_shaders, {"Path to the aov_shaders node graph.", std::string{}}},
{str::t_imager, {"Path to the imagers node graph.", std::string{}}},
};
return data;
}
Expand Down Expand Up @@ -622,6 +623,8 @@ void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& _key, const VtValu
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) { _atmosphere = p; });
} else if (key == str::t_aov_shaders) {
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) { _aov_shaders = p; });
} else if (key == str::t_imager) {
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) { _imager = p; });
} else if (key == str::t_subdiv_dicing_camera) {
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) {
_subdiv_dicing_camera = p;
Expand Down Expand Up @@ -815,6 +818,8 @@ VtValue HdArnoldRenderDelegate::GetRenderSetting(const TfToken& _key) const
return VtValue(_atmosphere.GetString());
} else if (key == str::t_aov_shaders) {
return VtValue(_aov_shaders.GetString());
} else if (key == str::t_imager) {
return VtValue(_imager.GetString());
} else if (key == str::t_subdiv_dicing_camera) {
return VtValue(_subdiv_dicing_camera.GetString());
}
Expand Down Expand Up @@ -1461,6 +1466,14 @@ std::vector<AtNode*> HdArnoldRenderDelegate::GetAovShaders(HdRenderIndex* render
return std::vector<AtNode *>();
}

AtNode* HdArnoldRenderDelegate::GetImager(HdRenderIndex* renderIndex)
{
const HdArnoldNodeGraph *nodeGraph = HdArnoldNodeGraph::GetNodeGraph(renderIndex, _imager);
if (nodeGraph)
return nodeGraph->GetTerminal(str::t_input);
return nullptr;
}

AtNode* HdArnoldRenderDelegate::GetSubdivDicingCamera(HdRenderIndex* renderIndex)
{
if (_subdiv_dicing_camera.IsEmpty())
Expand Down
8 changes: 8 additions & 0 deletions render_delegate/render_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,13 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
HDARNOLD_API
std::vector<AtNode*> GetAovShaders(HdRenderIndex* renderIndex);

/// Get the root of the imager graph
///
/// @param renderIndex Pointer to the Hydra render index.
/// @return Pointer to the imager node.
HDARNOLD_API
AtNode* GetImager(HdRenderIndex* renderIndex);

// Store the list of cryptomatte driver names, so that we can get the cryptomatte
// metadatas in their attribute "custom_attributes"
/// @param driver Name of a driver used for a cryptomatte AOVs (crypto_material, crypto_asset, crypto_object)
Expand Down Expand Up @@ -555,6 +562,7 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
SdfPath _background; ///< Path to the background shader.
SdfPath _atmosphere; ///< Path to the atmosphere shader.
SdfPath _aov_shaders; ///< Path to the aov shaders.
SdfPath _imager; ///< Path to the root imager node.
SdfPath _subdiv_dicing_camera; ///< Path to the subdiv dicing camera
AtUniverse* _universe; ///< Universe used by the Render Delegate.
#ifdef ARNOLD_MULTIPLE_RENDER_SESSIONS
Expand Down
16 changes: 15 additions & 1 deletion render_delegate/render_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens,
((tolerance, "arnold:layer_tolerance"))
((enableFiltering, "arnold:layer_enable_filtering"))
((halfPrecision, "arnold:layer_half_precision"))
(request_imager_update)
(sourceName)
(sourceType)
(dataType)
Expand Down Expand Up @@ -636,6 +637,11 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
updateAovs = true;
}

bool updateImagers = false;
AtNode* imager = _renderDelegate->GetImager(GetRenderIndex());
if (imager != static_cast<AtNode*>(AiNodeGetPtr(_mainDriver, str::input)))
updateImagers = true;

// Eventually set the subdiv dicing camera in the options
const AtNode *subdivDicingCamera = _renderDelegate->GetSubdivDicingCamera(GetRenderIndex());
if (subdivDicingCamera)
Expand Down Expand Up @@ -722,7 +728,7 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
// We expect Hydra to resize the render buffers.
const auto& delegateRenderProducts = _renderDelegate->GetDelegateRenderProducts();
if (_RenderBuffersChanged(aovBindings) || (!delegateRenderProducts.empty() && _deepProducts.empty()) ||
_usingFallbackBuffers || updateAovs) {
_usingFallbackBuffers || updateAovs || updateImagers) {
_usingFallbackBuffers = false;
renderParam->Interrupt();
_ClearRenderBuffers();
Expand Down Expand Up @@ -853,6 +859,11 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
TfStringPrintf(
"%s %s %s %s", aovName, arnoldTypes.outputString, filterName, AiNodeGetName(buffer.driver))
.c_str()};

if (!strcmp(aovName, "RGBA")) {
AiNodeSetPtr(buffer.driver, str::input, imager);
}

}
outputs.push_back(output);
}
Expand Down Expand Up @@ -955,6 +966,9 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
// finally add the user aov_shaders at the end so they can access all the AOVs
aovShaders.insert(aovShaders.end(), _aovShaders.begin(), _aovShaders.end());

// add the imager to the main driver
AiNodeSetPtr(_mainDriver, str::input, imager);

if (!outputs.empty()) {
AiNodeSetArray(
_renderDelegate->GetOptions(), str::outputs,
Expand Down
10 changes: 7 additions & 3 deletions translator/reader/prim_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ void UsdArnoldPrimReader::ReadAttribute(
}
}
// check if there are connections to this attribute
if (paramType != AI_TYPE_NODE && usdAttr.HasAuthoredConnections())
bool isImager = AiNodeEntryGetType(AiNodeGetNodeEntry(node)) == AI_NODE_DRIVER;
if ((paramType != AI_TYPE_NODE || isImager) && usdAttr.HasAuthoredConnections())
_ReadAttributeConnection(prim, usdAttr, node, arnoldAttr, time, context, paramType);
}
}
Expand Down Expand Up @@ -292,8 +293,11 @@ void UsdArnoldPrimReader::_ReadAttributeConnection(
}
}

context.AddConnection(node, arnoldAttr, target.GetPrimPath().GetText(),
UsdArnoldReader::CONNECTION_LINK, outputElement);
// if it's an imager then use a CONNECTION_PTR
context.AddConnection(node, arnoldAttr, target.GetPrimPath().GetText(),
AiNodeEntryGetType(AiNodeGetNodeEntry(node)) == AI_NODE_DRIVER ?
UsdArnoldReader::CONNECTION_PTR : UsdArnoldReader::CONNECTION_LINK,
outputElement);
}

void UsdArnoldPrimReader::_ReadArrayLink(
Expand Down
18 changes: 14 additions & 4 deletions translator/reader/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens,
((aovSettingName,"driver:parameters:aov:name"))
((aovGlobalAtmosphere, "arnold:global:atmosphere"))
((aovGlobalBackground, "arnold:global:background"))
((aovGlobalImager, "arnold:global:imager"))
((aovGlobalAovs, "arnold:global:aov_shaders"))
((colorSpaceLinear, "arnold:global:color_space_linear"))
((colorSpaceNarrow, "arnold:global:color_space_narrow"))
Expand Down Expand Up @@ -117,8 +118,8 @@ ArnoldAOVTypes _GetArnoldTypesFromTokenType(const TfToken& type)
}

// Read eventual connections to a ArnoldNodeGraph primitive, that acts as a passthrough
static inline void UsdArnoldNodeGraphConnection(AtNode *options, const UsdPrim &prim, const UsdAttribute &attr,
const std::string &attrName, UsdArnoldReaderContext &context)
static inline void UsdArnoldNodeGraphConnection(AtNode *node, const UsdPrim &prim, const UsdAttribute &attr,
const std::string &attrName, UsdArnoldReaderContext &context)
{
const TimeSettings &time = context.GetTimeSettings();
VtValue value;
Expand All @@ -143,7 +144,7 @@ static inline void UsdArnoldNodeGraphConnection(AtNode *options, const UsdPrim &
SdfPath outPath(sourcePaths[0].GetPrimPath());
UsdPrim outPrim = context.GetReader()->GetStage()->GetPrimAtPath(outPath);
if (outPrim) {
context.AddConnection(options, attrName, outPath.GetText(), UsdArnoldReader::CONNECTION_PTR);
context.AddConnection(node, attrName, outPath.GetText(), UsdArnoldReader::CONNECTION_PTR);
}
}
}
Expand Down Expand Up @@ -274,6 +275,8 @@ void UsdArnoldReadRenderSettings::Read(const UsdPrim &prim, UsdArnoldReaderConte
std::vector<std::string> outputs;
std::vector<std::string> lpes;
std::vector<AtNode *> aovShaders;
// collect beauty drivers from beauty outputs across all products, use a set as there be multiple
std::set<AtNode *> beautyDrivers;

// Every render product is translated as an arnold driver.
UsdRelationship productsRel = renderSettings.GetProductsRel();
Expand Down Expand Up @@ -459,7 +462,11 @@ void UsdArnoldReadRenderSettings::Read(const UsdPrim &prim, UsdArnoldReaderConte
output += std::string(" ") + arnoldTypes.outputString; // AOV type (RGBA, VECTOR, etc..)
output += std::string(" ") + filterName; // name of the filter for this AOV
output += std::string(" ") + productPrim.GetPath().GetText(); // name of the driver for this AOV


// Track beauty outputs drivers
if (aovName == "RGBA")
beautyDrivers.insert(driver);

// Add this output to the full list
outputs.push_back(output);
// also add the layer name in case we need to add it
Expand Down Expand Up @@ -549,6 +556,9 @@ void UsdArnoldReadRenderSettings::Read(const UsdPrim &prim, UsdArnoldReaderConte
UsdArnoldNodeGraphConnection(options, prim, prim.GetAttribute(_tokens->aovGlobalAtmosphere), "atmosphere", context);
UsdArnoldNodeGraphConnection(options, prim, prim.GetAttribute(_tokens->aovGlobalBackground), "background", context);
UsdArnoldNodeGraphAovConnection(options, prim, prim.GetAttribute(_tokens->aovGlobalAovs), "aov_shaders", context);
for (auto driver: beautyDrivers) {
UsdArnoldNodeGraphConnection(driver, prim, prim.GetAttribute(_tokens->aovGlobalImager), "input", context);
}

// Setup color manager
AtNode* colorManager;
Expand Down

0 comments on commit 1e2a2d3

Please sign in to comment.