Skip to content

Commit d3f03d5

Browse files
ld-kerleypixar-oss
authored andcommitted
[hdMtlx] Add unit tests for MaterialX 1.39
This test is checking the document upgrade process for USD files that contain mtlx nodes and are making use of the config:mtlx:version dictionary. Closes #3381 (Internal change: 2362886) (Internal change: 2363041)
1 parent 19fb0c5 commit d3f03d5

File tree

13 files changed

+507
-0
lines changed

13 files changed

+507
-0
lines changed

pxr/usdImaging/usdImaging/CMakeLists.txt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,59 @@ pxr_register_test(testUsdImagingStageSceneIndexContents
356356
DIFF_COMPARE
357357
basic.txt
358358
)
359+
360+
# This test requires MaterialX support and is not currently supported on static
361+
# builds as it uses a plugin mechanism which is not supported for static build
362+
# configurations.
363+
if (BUILD_SHARED_LIBS AND $PXR_ENABLE_MATERIALX_SUPPORT)
364+
365+
pxr_build_test(testUsdImagingHdMtlx
366+
LIBRARIES
367+
tf
368+
hd
369+
hdMtlx
370+
usdImaging
371+
CPPFILES
372+
testenv/testUsdImagingHdMtlx.cpp
373+
)
374+
pxr_install_test_dir(
375+
SRC testenv/testUsdImagingHdMtlx
376+
DEST testUsdImagingHdMtlx
377+
)
378+
pxr_register_test(testUsdImagingHdMtlx_withMtlxVersion
379+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingHdMtlx --filename withMtlxVersion.usda"
380+
EXPECTED_RETURN_CODE 0
381+
DIFF_COMPARE
382+
withMtlxVersion.mtlx
383+
TESTENV testUsdImagingHdMtlx
384+
)
385+
pxr_register_test(testUsdImagingHdMtlx_withoutMtlxVersion
386+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingHdMtlx --filename withoutMtlxVersion.usda"
387+
EXPECTED_RETURN_CODE 0
388+
DIFF_COMPARE
389+
withoutMtlxVersion.mtlx
390+
TESTENV testUsdImagingHdMtlx
391+
)
392+
pxr_register_test(testUsdImagingHdMtlx_atan2Node
393+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingHdMtlx --filename atan2Node.usda"
394+
EXPECTED_RETURN_CODE 0
395+
DIFF_COMPARE
396+
atan2Node.mtlx
397+
TESTENV testUsdImagingHdMtlx
398+
)
399+
pxr_register_test(testUsdImagingHdMtlx_switchNode
400+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingHdMtlx --filename switchNode.usda"
401+
EXPECTED_RETURN_CODE 0
402+
DIFF_COMPARE
403+
switchNode.mtlx
404+
TESTENV testUsdImagingHdMtlx
405+
)
406+
pxr_register_test(testUsdImagingHdMtlx_swizzleNode
407+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingHdMtlx --filename swizzleNode.usda"
408+
EXPECTED_RETURN_CODE 0
409+
DIFF_COMPARE
410+
swizzleNode.mtlx
411+
TESTENV testUsdImagingHdMtlx
412+
)
413+
414+
endif() # BUILD_SHARED_LIBS AND PXR_ENABLE_MATERIALX_SUPPORT

pxr/usdImaging/usdImaging/dataSourceMaterial.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class UsdImagingDataSourceMaterialPrim : public UsdImagingDataSourcePrim
9090
UsdImagingPropertyInvalidationType invalidationType);
9191

9292
private:
93+
USDIMAGING_API
9394
UsdImagingDataSourceMaterialPrim(
9495
const SdfPath &sceneIndexPath,
9596
const UsdPrim &usdPrim,
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
//
2+
// Copyright 2025 Pixar
3+
//
4+
// Licensed under the terms set forth in the LICENSE.txt file available at
5+
// https://openusd.org/license.
6+
//
7+
8+
#include "pxr/imaging/hdMtlx/hdMtlx.h"
9+
10+
#include "pxr/imaging/hd/dataSourceMaterialNetworkInterface.h"
11+
#include "pxr/imaging/hd/renderIndex.h"
12+
#include "pxr/imaging/hd/unitTestNullRenderDelegate.h"
13+
#include "pxr/imaging/hd/unitTestHelper.h"
14+
#include "pxr/usdImaging/usdImaging/dataSourceMaterial.h"
15+
#include "pxr/usdImaging/usdImaging/sceneIndices.h"
16+
#include "pxr/usdImaging/usdImaging/stageSceneIndex.h"
17+
#include "pxr/usdImaging/usdImaging/materialParamUtils.h"
18+
19+
#include "pxr/usd/usd/stage.h"
20+
#include "pxr/usd/usd/primRange.h"
21+
#include "pxr/usd/usdShade/material.h"
22+
23+
#include "pxr/base/tf/errorMark.h"
24+
25+
#include <MaterialXFormat/XmlIo.h>
26+
27+
#include <iostream>
28+
29+
PXR_NAMESPACE_USING_DIRECTIVE
30+
31+
32+
TF_DEFINE_PRIVATE_TOKENS(
33+
_tokens,
34+
(mtlx)
35+
(material)
36+
((mtlxVersion, "mtlx:version"))
37+
);
38+
39+
namespace mx = MaterialX;
40+
41+
// NOTE: This class is copied from testUsdImagingDataSourceAttribute.cpp
42+
class TestStageGlobals : public UsdImagingDataSourceStageGlobals {
43+
public:
44+
TestStageGlobals() : _time(0) {}
45+
~TestStageGlobals() override = default;
46+
47+
UsdTimeCode GetTime() const override { return UsdTimeCode(_time); }
48+
49+
void FlagAsTimeVarying(
50+
const SdfPath &hydraPath,
51+
const HdDataSourceLocator &locator) const override {
52+
_timeVarying[hydraPath].insert(locator);
53+
}
54+
55+
void FlagAsAssetPathDependent(const SdfPath &usdPath) const override {
56+
_assetPathDependent.insert(usdPath);
57+
}
58+
59+
HdDataSourceLocatorSet const &
60+
GetTimeVaryingLocators(SdfPath const &hydraPath) const {
61+
return _timeVarying[hydraPath];
62+
}
63+
64+
std::set<SdfPath> const &GetAssetPathDependents() const {
65+
return _assetPathDependent;
66+
}
67+
68+
private:
69+
double _time;
70+
mutable std::map<SdfPath, HdDataSourceLocatorSet> _timeVarying;
71+
mutable std::set<SdfPath> _assetPathDependent;
72+
};
73+
74+
// Replace the given filename extension with 'mtlx'
75+
static std::string
76+
_CreateMtlxFilename(std::string filename)
77+
{
78+
size_t extPos = filename.find_last_of(".");
79+
return filename.replace(extPos, filename.length() - extPos, ".mtlx");
80+
}
81+
82+
bool
83+
TestHdMtlx(const std::string& inputFilename)
84+
{
85+
UsdStageRefPtr stage = UsdStage::Open(inputFilename);
86+
UsdTimeCode frame(0);
87+
88+
Hd_UnitTestNullRenderDelegate renderDelegate;
89+
std::unique_ptr<HdRenderIndex> renderIndex(
90+
HdRenderIndex::New(&renderDelegate, HdDriverVector()));
91+
92+
UsdImagingCreateSceneIndicesInfo info;
93+
info.stage = stage;
94+
95+
const UsdImagingSceneIndices sceneIndices =
96+
UsdImagingCreateSceneIndices(info);
97+
UsdImagingStageSceneIndexRefPtr stageSceneIndex =
98+
sceneIndices.stageSceneIndex;
99+
stageSceneIndex->SetTime(frame);
100+
101+
for (const auto& prim : stage->TraverseAll()) {
102+
if (!prim.IsA<UsdShadeMaterial>()) {
103+
continue;
104+
}
105+
106+
// Get the MaterialX Material DataSource
107+
const SdfPath materialPath = prim.GetPath();
108+
TestStageGlobals stageGlobals;
109+
auto imgPrimDs = UsdImagingDataSourceMaterialPrim::New(
110+
materialPath, stage->GetPrimAtPath(materialPath), stageGlobals);
111+
112+
UsdImagingDataSourceMaterialHandle materialDs =
113+
UsdImagingDataSourceMaterial::Cast(
114+
imgPrimDs->Get(_tokens->material));
115+
HdContainerDataSourceHandle mtlxNetworkDs =
116+
HdContainerDataSource::Cast(materialDs->Get(_tokens->mtlx));
117+
118+
// Get the HdMaterialNetwork
119+
HdSceneIndexPrim hdPrim = stageSceneIndex->GetPrim(materialPath);
120+
if (hdPrim.primType.IsEmpty()) {
121+
std::cout << " - No prim type for <" << materialPath << ">\n";
122+
return false;
123+
}
124+
HdDataSourceMaterialNetworkInterface hdNetInterfaceDs =
125+
HdDataSourceMaterialNetworkInterface(
126+
materialPath, mtlxNetworkDs, hdPrim.dataSource);
127+
128+
// Get the terminal node from the Material Network
129+
TfTokenVector terminalNames = hdNetInterfaceDs.GetTerminalNames();
130+
if (terminalNames.empty()) {
131+
std::cout << "No terminals defined on <" << materialPath << ">.\n";
132+
return false;
133+
}
134+
const TfToken terminalType = terminalNames[0];
135+
const auto terminalNodeConn =
136+
hdNetInterfaceDs.GetTerminalConnection(terminalType);
137+
if (!terminalNodeConn.first) {
138+
std::cout << "No terminal node for type '" << terminalType << "'.\n";
139+
return false;
140+
}
141+
142+
// Create MaterialX Document
143+
const mx::DocumentPtr &stdLibraries = HdMtlxStdLibraries();
144+
TfToken terminalNodeName = terminalNodeConn.second.upstreamNodeName;
145+
TfTokenVector terminalNodeConnectionNames =
146+
hdNetInterfaceDs.GetNodeInputConnectionNames(terminalNodeName);
147+
148+
HdMtlxTexturePrimvarData *mxHdData = nullptr;
149+
MaterialX::DocumentPtr mtlxDoc =
150+
HdMtlxCreateMtlxDocumentFromHdMaterialNetworkInterface(
151+
&hdNetInterfaceDs, terminalNodeName,
152+
terminalNodeConnectionNames,
153+
stdLibraries, mxHdData);
154+
155+
// Write out the MaterialX document
156+
mx::XmlWriteOptions mxWriteOptions;
157+
mxWriteOptions.elementPredicate = [](mx::ConstElementPtr elem) -> bool {
158+
// skip writing all includes for brevity
159+
return !elem->hasSourceUri();
160+
};
161+
162+
const std::string outputFilename = _CreateMtlxFilename(inputFilename);
163+
mx::writeToXmlFile(mtlxDoc, outputFilename, &mxWriteOptions);
164+
}
165+
return true;
166+
}
167+
168+
169+
int main(int argc, char *argv[])
170+
{
171+
std::string inputFilename = "";
172+
for (int i = 0; i < argc; ++i) {
173+
const std::string arg(argv[i]);
174+
175+
if (arg == "--filename") {
176+
inputFilename = mx::FilePath(argv[++i]);
177+
}
178+
}
179+
180+
if (inputFilename.empty() ) {
181+
std::cout << "--filename is required.";
182+
return EXIT_FAILURE;
183+
}
184+
185+
TfErrorMark mark;
186+
bool success = TestHdMtlx(inputFilename);
187+
188+
if (success && mark.IsClean()) {
189+
std::cout << "OK" << std::endl;
190+
return EXIT_SUCCESS;
191+
} else {
192+
std::cout << "FAILED" << std::endl;
193+
return EXIT_FAILURE;
194+
}
195+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#usda 1.0
2+
3+
def "MaterialX"
4+
{
5+
def "Materials"
6+
{
7+
def Material "Atan2Example" (
8+
prepend apiSchemas = ["MaterialXConfigAPI"]
9+
)
10+
{
11+
string config:mtlx:version = "1.38"
12+
token outputs:mtlx:surface.connect = </MaterialX/Materials/Atan2Example/UsdPreviewSurface.outputs:surface>
13+
14+
def Shader "UsdPreviewSurface"
15+
{
16+
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
17+
color3f inputs:diffuseColor = (0.10470402, 0.24188282, 0.818)
18+
float inputs:metallic.connect = </MaterialX/Materials/Atan2Example/NodeGraphs/atan2.outputs:out>
19+
token outputs:surface
20+
}
21+
22+
def "NodeGraphs"
23+
{
24+
def Shader "atan2"
25+
{
26+
uniform token info:id = "ND_atan2_float"
27+
float inputs:in1 = 0.2
28+
float inputs:in2 = 0.7
29+
float outputs:out
30+
}
31+
}
32+
}
33+
}
34+
}
35+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.39">
3+
<UsdPreviewSurface name="Surface" type="surfaceshader">
4+
<input name="metallic" type="float" output="metallic_out" nodegraph="NodeGraphs" />
5+
<input name="diffuseColor" type="color3" value="0.104704, 0.241883, 0.818" />
6+
</UsdPreviewSurface>
7+
<surfacematerial name="Atan2Example" type="material">
8+
<input name="surfaceshader" type="surfaceshader" nodename="Surface" />
9+
</surfacematerial>
10+
<nodegraph name="NodeGraphs">
11+
<atan2 name="atan2" type="float" nodedef="ND_atan2_float">
12+
<input name="iny" type="float" value="0.2" />
13+
<input name="inx" type="float" value="0.7" />
14+
</atan2>
15+
<output name="metallic_out" type="float" nodename="atan2" />
16+
</nodegraph>
17+
</materialx>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.39">
3+
<standard_surface name="Surface" type="surfaceshader">
4+
<input name="base" type="float" output="base_out" nodegraph="NodeGraphs" />
5+
</standard_surface>
6+
<surfacematerial name="SwitchExample" type="material">
7+
<input name="surfaceshader" type="surfaceshader" nodename="Surface" />
8+
</surfacematerial>
9+
<nodegraph name="NodeGraphs">
10+
<switch name="switch" type="float" nodedef="ND_switch_floatI">
11+
<input name="in1" type="float" value="0.2" />
12+
<input name="in2" type="float" value="0.4" />
13+
<input name="which" type="integer" value="0" />
14+
</switch>
15+
<output name="base_out" type="float" nodename="switch" />
16+
</nodegraph>
17+
</materialx>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.39">
3+
<standard_surface name="Surface" type="surfaceshader">
4+
<input name="base_color" type="color3" output="base_color_out" nodegraph="_" />
5+
</standard_surface>
6+
<surfacematerial name="SwizzleExample" type="material">
7+
<input name="surfaceshader" type="surfaceshader" nodename="Surface" />
8+
</surfacematerial>
9+
<nodegraph name="_">
10+
<ramplr name="ramplr" type="color3" nodedef="ND_ramplr_color3">
11+
<input name="texcoord" type="vector2" nodename="geompropvalue" />
12+
<input name="valuel" type="color3" nodename="dot" />
13+
<input name="valuer" type="color3" nodename="swizzle" />
14+
</ramplr>
15+
<geompropvalue name="geompropvalue" type="vector2" nodedef="ND_geompropvalue_vector2">
16+
<input name="geomprop" type="string" value="st" />
17+
</geompropvalue>
18+
<dot name="dot" type="color3" nodedef="ND_dot_color3">
19+
<input name="in" type="color3" value="0, 0.5, 1" />
20+
</dot>
21+
<separate3 name="separate" type="multioutput">
22+
<input name="in" type="color3" nodename="dot" />
23+
</separate3>
24+
<combine3 name="swizzle" type="color3">
25+
<input name="in1" type="float" nodename="separate" output="outb" />
26+
<input name="in2" type="float" nodename="separate" output="outg" />
27+
<input name="in3" type="float" nodename="separate" output="outr" />
28+
</combine3>
29+
<output name="base_color_out" type="color3" nodename="ramplr" />
30+
</nodegraph>
31+
</materialx>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.39">
3+
<UsdPreviewSurface name="Surface" type="surfaceshader">
4+
<input name="clearcoat" type="float" value="1" />
5+
<input name="clearcoatRoughness" type="float" value="0" />
6+
<input name="diffuseColor" type="color3" value="0.0518895, 0.29606, 0.425324" />
7+
<input name="roughness" type="float" value="0.4" />
8+
</UsdPreviewSurface>
9+
<surfacematerial name="USD_CarPaint" type="material">
10+
<input name="surfaceshader" type="surfaceshader" nodename="Surface" />
11+
</surfacematerial>
12+
</materialx>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.39">
3+
<standard_surface name="Surface" type="surfaceshader">
4+
<input name="base" type="float" value="0.2" />
5+
<input name="base_color" type="color3" value="0.2, 0.4, 0.2" />
6+
</standard_surface>
7+
<surfacematerial name="StdSurface" type="material">
8+
<input name="surfaceshader" type="surfaceshader" nodename="Surface" />
9+
</surfacematerial>
10+
</materialx>

0 commit comments

Comments
 (0)