Skip to content

Commit

Permalink
use SdfPathVector for aov_shaders (#1322)
Browse files Browse the repository at this point in the history
* use SdfPathVector for aov_shaders

* read multiple aov_shaders in the procedural + test

* handle conversion from VtValue to SdfPathVector
  • Loading branch information
cpichard authored Oct 19, 2022
1 parent 4fba0d9 commit d74c750
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 35 deletions.
17 changes: 17 additions & 0 deletions common/common_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ void ArnoldUsdCheckForSdfPathValue(const VtValue& value, F&& f)
}
}

template <typename F>
ARCH_HIDDEN
void ArnoldUsdCheckForSdfPathVectorValue(const VtValue& value, F&& f)
{
if (value.IsHolding<SdfPathVector>()) {
f(value.UncheckedGet<SdfPathVector>());
} else if (value.IsHolding<std::string>()) {
// Split with space
const auto s = value.UncheckedGet<std::string>();
SdfPathVector paths;
for (const auto &path: TfStringTokenize(s)) {
paths.emplace_back(path);
}
f(paths);
}
}

ARCH_HIDDEN
int ArnoldUsdGetLogVerbosityFromFlags(int flags);

Expand Down
20 changes: 14 additions & 6 deletions render_delegate/render_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& _key, const VtValu
} else if (key == str::t_atmosphere) {
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) { _atmosphere = p; });
} else if (key == str::t_aov_shaders) {
ArnoldUsdCheckForSdfPathValue(value, [&](const SdfPath& p) { _aov_shaders = p; });
ArnoldUsdCheckForSdfPathVectorValue(value, [&](const SdfPathVector& 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) {
Expand Down Expand Up @@ -817,7 +817,10 @@ VtValue HdArnoldRenderDelegate::GetRenderSetting(const TfToken& _key) const
} else if (key == str::t_atmosphere) {
return VtValue(_atmosphere.GetString());
} else if (key == str::t_aov_shaders) {
return VtValue(_aov_shaders.GetString());
// There should be a function in common_utils.cpp
std::vector<std::string> pathsAsString;
std::transform(_aov_shaders.begin(), _aov_shaders.end(), std::back_inserter(pathsAsString), [](const auto &p){return p.GetString();});
return VtValue(TfStringJoin(pathsAsString));
} else if (key == str::t_imager) {
return VtValue(_imager.GetString());
} else if (key == str::t_subdiv_dicing_camera) {
Expand Down Expand Up @@ -1460,10 +1463,15 @@ AtNode* HdArnoldRenderDelegate::GetAtmosphere(HdRenderIndex* renderIndex)

std::vector<AtNode*> HdArnoldRenderDelegate::GetAovShaders(HdRenderIndex* renderIndex)
{
const HdArnoldNodeGraph *nodeGraph = HdArnoldNodeGraph::GetNodeGraph(renderIndex, _aov_shaders);
if (nodeGraph)
return nodeGraph->GetTerminals(_tokens->aovShadersArray);
return std::vector<AtNode *>();
std::vector<AtNode *> nodes;
for (const auto &materialPath: _aov_shaders) {
const HdArnoldNodeGraph *nodeGraph = HdArnoldNodeGraph::GetNodeGraph(renderIndex, materialPath);
if (nodeGraph) {
const auto &terminals = nodeGraph->GetTerminals(_tokens->aovShadersArray);
std::copy(terminals.begin(), terminals.end(), std::back_inserter(nodes));
}
}
return nodes;
}

AtNode* HdArnoldRenderDelegate::GetImager(HdRenderIndex* renderIndex)
Expand Down
2 changes: 1 addition & 1 deletion render_delegate/render_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
SdfPath _id; ///< Path of the Render Delegate.
SdfPath _background; ///< Path to the background shader.
SdfPath _atmosphere; ///< Path to the atmosphere shader.
SdfPath _aov_shaders; ///< Path to the aov shaders.
SdfPathVector _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.
Expand Down
7 changes: 7 additions & 0 deletions testsuite/test_1321/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Allow list of AOV ArnoldNodeGraph primitives in RenderSettings

See #1321

author: cyril.pichard

PARAMS: {'scene':'test.usda', 'output_image': 'testrender.exr', 'reference_image':'ref/reference.exr' }
238 changes: 238 additions & 0 deletions testsuite/test_1321/data/test.usda

Large diffs are not rendered by default.

Binary file added testsuite/test_1321/ref/reference.exr
Binary file not shown.
58 changes: 30 additions & 28 deletions translator/reader/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <vector>

#include <pxr/base/tf/pathUtils.h>
#include <pxr/base/tf/stringUtils.h>
#include <pxr/usd/usdRender/product.h>
#include <pxr/usd/usdRender/settings.h>
#include <pxr/usd/usdRender/var.h>
Expand Down Expand Up @@ -160,36 +161,37 @@ static inline void UsdArnoldNodeGraphAovConnection(AtNode *options, const UsdPri
const TimeSettings &time = context.GetTimeSettings();
VtValue value;
if (attr && attr.Get(&value, time.frame)) {
// RenderSettings have a string attribute, referencing a prim in the stage
// RenderSettings have a string attribute, referencing multiple prims in the stage
std::string valStr = VtValueGetString(value, &attr);
if (!valStr.empty()) {
SdfPath path(valStr);
// We check if there is a primitive at the path of this string
UsdPrim ngPrim = context.GetReader()->GetStage()->GetPrimAtPath(SdfPath(valStr));
// We verify if the primitive is indeed a ArnoldNodeGraph
if (ngPrim && ngPrim.GetTypeName() == _tokens->ArnoldNodeGraph) {
AtArray* array = AiNodeGetArray(options, str::aov_shaders);
unsigned numElements = AiArrayGetNumElements(array);
// We can use a UsdShadeShader schema in order to read connections
UsdShadeShader ngShader(ngPrim);
for (unsigned i=1;; i++) {
// the output terminal name will be aov_shader:i{1,...,n} as a contiguous array
TfToken outputName(attrBase + std::string(":i") + std::to_string(i));
UsdShadeOutput outputAttr = ngShader.GetOutput(outputName);
if (!outputAttr)
break;
SdfPathVector sourcePaths;
// Check which shader is connected to this output
if (outputAttr.HasConnectedSource() && outputAttr.GetRawConnectedSourcePaths(&sourcePaths) &&
!sourcePaths.empty()) {
SdfPath outPath(sourcePaths[0].GetPrimPath());
UsdPrim outPrim = context.GetReader()->GetStage()->GetPrimAtPath(outPath);
if (outPrim) {
// we connect to aov_shaders{0,...,n-1} parameters i.e. 0 indexed, offset from any previous connections
unsigned index = numElements + i-1;
std::string outputElement = attrBase + "[" + std::to_string(index) + "]";
context.AddConnection(options, outputElement, outPath.GetText(),
UsdArnoldReader::CONNECTION_PTR);
AtArray* aovShadersArray = AiNodeGetArray(options, str::aov_shaders);
unsigned numElements = AiArrayGetNumElements(aovShadersArray);
for(const auto &nodeGraphPrimName: TfStringTokenize(valStr)) {
SdfPath nodeGraphPrimPath(nodeGraphPrimName);
// We check if there is a primitive at the path of this string
UsdPrim nodeGraphPrim = context.GetReader()->GetStage()->GetPrimAtPath(nodeGraphPrimPath);
if (nodeGraphPrim && nodeGraphPrim.GetTypeName() == _tokens->ArnoldNodeGraph) {
// We can use a UsdShadeShader schema in order to read connections
UsdShadeShader ngShader(nodeGraphPrim);
for (unsigned aovShaderIndex=1;; aovShaderIndex++) {
// the output terminal name will be aov_shader:i{1,...,n} as a contiguous array
TfToken outputName(attrBase + std::string(":i") + std::to_string(aovShaderIndex));
UsdShadeOutput outputAttr = ngShader.GetOutput(outputName);
if (!outputAttr) {
break;
}
SdfPathVector sourcePaths;
// Check which shader is connected to this output
if (outputAttr.HasConnectedSource() && outputAttr.GetRawConnectedSourcePaths(&sourcePaths)) {
for(const SdfPath &aovShaderPath : sourcePaths) {
SdfPath aovShaderPrimPath(aovShaderPath.GetPrimPath());
UsdPrim outPrim = context.GetReader()->GetStage()->GetPrimAtPath(aovShaderPrimPath);
if (outPrim) {
// we connect to aov_shaders{0,...,n-1} parameters i.e. 0 indexed, offset from any previous connections
std::string optionAovShaderElement = attrBase + "[" + std::to_string(numElements++) + "]";
context.AddConnection(options, optionAovShaderElement, aovShaderPrimPath.GetText(), UsdArnoldReader::CONNECTION_PTR);
}
}
}
}
}
Expand Down

0 comments on commit d74c750

Please sign in to comment.