Skip to content

Commit

Permalink
Parse MaterialX metadata into SdrProperty
Browse files Browse the repository at this point in the history
Fixes PixarAnimationStudios#1874

- "enum" and "enumvalues" are parsed as options
- "doc" is parsed as help
- "uiname" is parsed as label
- "uifolder" is parsed as page
- all other MaterialX metadata is added as hints
  • Loading branch information
JGamache-autodesk authored and seando-adsk committed Nov 15, 2022
1 parent 462d2de commit 685adc8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 3 deletions.
105 changes: 105 additions & 0 deletions pxr/usd/usdMtlx/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ TF_DEFINE_PRIVATE_TOKENS(

((discoveryType, "mtlx"))
((sourceType, ""))

(uimin)
(uimax)
(uisoftmin)
(uisoftmax)
(uistep)
(unit)
(unittype)
);

// This environment variable lets users override the name of the primary
Expand Down Expand Up @@ -124,6 +132,73 @@ struct ShaderBuilder {
std::map<std::string, std::string> _propertyNameRemapping;
};

static
void
ParseMetadata(
NdrTokenMap& metadata,
const TfToken& key,
const mx::ConstElementPtr& element,
const std::string& attribute)
{
const auto& value = element->getAttribute(attribute);
if (!value.empty()) {
metadata.emplace(key, value);
}
}

static
void
ParseOptions(
NdrOptionVec& options,
const mx::ConstElementPtr& element
)
{
const auto& enumLabels = element->getAttribute("enum");
if (enumLabels.empty()) {
return;
}

const auto& enumValues = element->getAttribute("enumvalues");
std::vector<std::string> allLabels = UsdMtlxSplitStringArray(enumLabels);
std::vector<std::string> allValues = UsdMtlxSplitStringArray(enumValues);

if (allValues.size() && allValues.size() != allLabels.size()) {
// An array of vector2 values will produce twice the expected number of
// elements. We can fix that by regrouping them.
if (allValues.size() > allLabels.size() &&
allValues.size() % allLabels.size() == 0) {

size_t stride = allValues.size() / allLabels.size();
std::vector<std::string> rebuiltValues;
std::string currentValue;
for (size_t i = 0; i < allValues.size(); ++i) {
if (i % stride != 0) {
currentValue += mx::ARRAY_PREFERRED_SEPARATOR;
}
currentValue += allValues[i];
if ((i+1) % stride == 0) {
rebuiltValues.push_back(currentValue);
currentValue = "";
}
}
allValues.swap(rebuiltValues);
} else {
// Can not reconcile the size difference:
allValues.clear();
}
}

auto itLabels = allLabels.cbegin();
auto itValues = allValues.cbegin();
while (itLabels != allLabels.cend()) {
TfToken value;
if (itValues != allValues.cend()) {
value = TfToken(*itValues++);
}
options.emplace_back(TfToken(*itLabels++), value);
}
}

void
ShaderBuilder::AddProperty(
const mx::ConstTypedElementPtr& element,
Expand Down Expand Up @@ -242,6 +317,36 @@ ShaderBuilder::AddProperty(
metadata[SdrPropertyMetadata->ImplementationName] = j->second;
}

if (!isOutput) {
ParseMetadata(metadata, SdrPropertyMetadata->Label, element, "uiname");
ParseMetadata(metadata, SdrPropertyMetadata->Help, element, "doc");
ParseMetadata(metadata, SdrPropertyMetadata->Page, element, "uifolder");

ParseMetadata(metadata, _tokens->uimin, element, "uimin");
ParseMetadata(metadata, _tokens->uimax, element, "uimax");
ParseMetadata(metadata, _tokens->uisoftmin, element, "uisoftmin");
ParseMetadata(metadata, _tokens->uisoftmax, element, "uisoftmax");
ParseMetadata(metadata, _tokens->uistep, element, "uistep");
ParseMetadata(metadata, _tokens->unit, element, "unit");
ParseMetadata(metadata, _tokens->unittype, element, "unittype");

for (const auto& pair : metadata) {
const TfToken attrName = pair.first;
const std::string attrValue = pair.second;

if (std::find(SdrPropertyMetadata->allTokens.begin(),
SdrPropertyMetadata->allTokens.end(),
attrName) != SdrPropertyMetadata->allTokens.end()){
continue;
}

// Attribute hasn't been handled yet, so put it into the hints dict
hints.insert({attrName, attrValue});
}

ParseOptions(options, element);
}

// Add the property.
properties.push_back(
SdrShaderPropertyUniquePtr(
Expand Down
34 changes: 34 additions & 0 deletions pxr/usd/usdMtlx/testenv/testUsdMtlxParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,40 @@ def test_NodeParser(self):
self.assertEqual(sorted(node.GetInputNames()), ["in", "note"])
self.assertEqual(node.GetOutputNames(), ['out'])

# Verify some metadata:
node = Sdr.Registry().GetShaderNodeByIdentifier(
'UsdMtlxTestNamespace:nd_vector')
self.assertEqual(node.GetHelp(), "Vector help")
# Properties without a Page metadata end up in an unnamed page. This
# means that all MaterialX outputs will be assigned to the unnamed page
# when the metadata is used.
self.assertEqual(node.GetPages(), ["UI Page", ""])
self.assertEqual(node.GetPropertyNamesForPage("UI Page"), ["in",])
self.assertEqual(node.GetPropertyNamesForPage(""), ["note", "out"])
input = node.GetInput("in")
self.assertEqual(input.GetHelp(), "Property help")
self.assertEqual(input.GetLabel(), "UI Vector")
self.assertEqual(input.GetPage(), "UI Page")
self.assertEqual(input.GetOptions(),
[("X", "1, 0, 0"), ("Y", "0, 1, 0"), ("Z", "0, 0, 1")])

node = Sdr.Registry().GetShaderNodeByIdentifier(
'UsdMtlxTestNamespace:nd_float')
expected = {
"uimin": "-360.0",
"uimax": "360.0",
"uisoftmin": "0.0",
"uisoftmax": "180.0",
"uistep": "1.0",
"unittype": "angle",
"unit": "degree"
}
hints = node.GetInput("in").GetHints()
metadata = node.GetInput("in").GetMetadata()
for key in expected.keys():
self.assertEqual(hints[key], expected[key])
self.assertEqual(metadata[key], expected[key])

# Verify converted types.
typeNameMap = {
'boolean': 'bool',
Expand Down
6 changes: 3 additions & 3 deletions pxr/usd/usdMtlx/testenv/testUsdMtlxParser.testenv/test.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<output name="out" type="integer" />
</nodedef>
<nodedef name="nd_float" node="UsdMtlxTestNode">
<input name="in" type="float" />
<input name="in" type="float" uimin="-360.0" uimax="360.0" uisoftmin="0.0" uisoftmax="180.0" uistep="1.0" unittype="angle" unit="degree" />
<input name="note" type="string" value="" uniform="true" />
<output name="out" type="float" />
</nodedef>
Expand All @@ -15,8 +15,8 @@
<input name="note" type="string" value="" uniform="true" />
<output name="out" type="string" />
</nodedef>
<nodedef name="nd_vector" node="UsdMtlxTestNode">
<input name="in" type="vector3" />
<nodedef name="nd_vector" node="UsdMtlxTestNode" doc="Vector help">
<input name="in" type="vector3" enum="X,Y,Z" enumvalues="1,0,0, 0,1,0, 0,0,1" doc="Property help" uiname="UI Vector" uifolder="UI Page" />
<input name="note" type="string" value="" uniform="true" />
<output name="out" type="vector3" />
</nodedef>
Expand Down

0 comments on commit 685adc8

Please sign in to comment.