Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-133671 - Add textured mode handling to topo grapher #4031

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions lib/mayaUsd/render/MaterialXGenOgsXml/ShaderGenUtil.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "ShaderGenUtil.h"

#include "LobePruner.h"
#include "MaterialXCore/Types.h"

#include <mayaUsd/render/MaterialXGenOgsXml/CombinedMaterialXVersion.h>

Expand Down Expand Up @@ -56,17 +57,26 @@ const std::string& TopoNeutralGraph::getMaterialName()
return kMaterialName;
}

TopoNeutralGraph::TopoNeutralGraph(const mx::ElementPtr& material) { computeGraph(material); }
TopoNeutralGraph::TopoNeutralGraph(const mx::ElementPtr& material) { computeGraph(material, true); }

TopoNeutralGraph::TopoNeutralGraph(
const mx::ElementPtr& material,
const LobePruner::Ptr& lobePruner)
{
_lobePruner = lobePruner;
computeGraph(material);
computeGraph(material, true);
}

void TopoNeutralGraph::computeGraph(const mx::ElementPtr& material)
TopoNeutralGraph::TopoNeutralGraph(
const mx::ElementPtr& material,
const LobePruner::Ptr& lobePruner,
bool textured)
{
_lobePruner = lobePruner;
computeGraph(material, textured);
}

void TopoNeutralGraph::computeGraph(const mx::ElementPtr& material, bool textured)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one comment. Alice had recommended that I move away from having boolean parameters like this in favour of multiple methods. So in this case something like computeGraph and computeTexturedGraph. Just a suggestion though, up to you. I do think its a bit nicer that way.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I guess the downside of that is you'd need an if statement on the textured parameter to call either computeGraph or computeTexturedGraph.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then the code of both functions end up identical except for three lines of code. I know of other C++ gurus that have a strict policy of using fully specified enums in this case. Especially useful when you start having calls like:

doSomething(true, false, true, true, false, false, false);

Sadly not something I can rework in the mayaUsdApi library as it needs to stay binary compatible. I can add constructors, but that is about it.

{
if (!material) {
throw mx::Exception("Invalid material element");
Expand Down Expand Up @@ -138,7 +148,25 @@ void TopoNeutralGraph::computeGraph(const mx::ElementPtr& material)
if (!sourceInput) {
continue;
}
auto connectedNode = sourceInput->getConnectedNode();
auto connectedNode = sourceInput->getConnectedNode();

// In textured mode we traverse everything, but in untextured mode we only traverse PBR
// level connections.
static const auto kPbrConnectionTypes = std::set<std::string>
{
#if MX_COMBINED_VERSION >= 13807
mx::BSDF_TYPE_STRING, mx::EDF_TYPE_STRING, mx::VDF_TYPE_STRING,
#else
"BSDF", "EDF", "VDF",
#endif
mx::SURFACE_SHADER_TYPE_STRING, mx::DISPLACEMENT_SHADER_TYPE_STRING,
mx::VOLUME_SHADER_TYPE_STRING
};

if (!textured && kPbrConnectionTypes.count(sourceInput->getType()) == 0) {
connectedNode = nullptr;
}

const std::string defaultGeomPropString = gatherDefaultGeomProp(*sourceInput);
if (connectedNode) {
auto destConnectedIt = _nodeMap.find(connectedNode->getNamePath());
Expand Down
30 changes: 28 additions & 2 deletions lib/mayaUsd/render/MaterialXGenOgsXml/ShaderGenUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,34 @@ namespace ShaderGenUtil {
class MAYAUSD_CORE_PUBLIC TopoNeutralGraph
{
public:
/*! Creates a barebones TopoNeutralGraph that will process the provided material and generate a
* topo neutral version of it.
* @param[in] material the material to process
*/
explicit TopoNeutralGraph(const mx::ElementPtr& material);
explicit TopoNeutralGraph(const mx::ElementPtr& material, const LobePruner::Ptr& library);

/*! Creates a TopoNeutralGraph that will process the provided material and generate a topo
* neutral version of it. It will also substitute lobe pruned categories if a LobePruner is
* provided.
* @param[in] material the material to process
* @param[in] lobePruner an instance of a LobePruner. These are usually singletons that
* accumulate pruned NodeDefs
*/
TopoNeutralGraph(const mx::ElementPtr& material, const LobePruner::Ptr& lobePruner);

/*! Creates a TopoNeutralGraph that will process the provided material and generate a topo
* neutral version of it. It will also substitute lobe pruned categories if a LobePruner is
* provided.
* @param[in] material the material to process
* @param[in] lobePruner an instance of a LobePruner. These are usually singletons that
* accumulate pruned NodeDefs
* @param[in] textured is true if the full material is to be processed. When false, we will
* generate an untextured topo neutral material instead
*/
TopoNeutralGraph(
const mx::ElementPtr& material,
const LobePruner::Ptr& lobePruner,
bool textured);
~TopoNeutralGraph() = default;

TopoNeutralGraph() = delete;
Expand Down Expand Up @@ -57,7 +83,7 @@ class MAYAUSD_CORE_PUBLIC TopoNeutralGraph
mx::NodeGraphPtr& getNodeGraph();

protected:
void computeGraph(const mx::ElementPtr& material);
void computeGraph(const mx::ElementPtr& material, bool textured);
mx::NodePtr cloneNode(const mx::Node& node, mx::GraphElement& container);
mx::OutputPtr findNodeGraphOutput(const mx::Input& input, const std::string& outputName);
std::string gatherChannels(const mx::Input& input);
Expand Down
16 changes: 16 additions & 0 deletions lib/mayaUsdAPI/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ struct TopoNeutralGraphImpl
{
}

TopoNeutralGraphImpl(
const MaterialX::ElementPtr& material,
const LobePruner::Ptr& lobePruner,
bool textured)
: _topoGraph(material, lobePruner->_imp->_lobePruner, textured)
{
}

MaterialXMaya::ShaderGenUtil::TopoNeutralGraph _topoGraph;
};

Expand All @@ -184,6 +192,14 @@ TopoNeutralGraph::TopoNeutralGraph(
{
}

TopoNeutralGraph::TopoNeutralGraph(
const MaterialX::ElementPtr& material,
const LobePruner::Ptr& lobePruner,
bool textured)
: _imp(new TopoNeutralGraphImpl(material, lobePruner, textured))
{
}

// When using a pimpl you need to define the destructor here in the
// .cpp so the compiler has access to the impl.
TopoNeutralGraph::~TopoNeutralGraph() = default;
Expand Down
30 changes: 28 additions & 2 deletions lib/mayaUsdAPI/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,34 @@ class MAYAUSD_API_PUBLIC LobePruner
class MAYAUSD_API_PUBLIC TopoNeutralGraph
{
public:
TopoNeutralGraph(const MaterialX::ElementPtr&);
TopoNeutralGraph(const MaterialX::ElementPtr&, const LobePruner::Ptr& lobePruner);
/*! Creates a barebones TopoNeutralGraph that will process the provided material and generate a
* topo neutral version of it.
* @param[in] material the material to process
*/
TopoNeutralGraph(const MaterialX::ElementPtr& material);

/*! Creates a TopoNeutralGraph that will process the provided material and generate a topo
* neutral version of it. It will also substitute lobe pruned categories if a LobePruner is
* provided.
* @param[in] material the material to process
* @param[in] lobePruner an instance of a LobePruner. These are usually singletons that
* accumulate pruned NodeDefs
*/
TopoNeutralGraph(const MaterialX::ElementPtr& material, const LobePruner::Ptr& lobePruner);

/*! Creates a TopoNeutralGraph that will process the provided material and generate a topo
* neutral version of it. It will also substitute lobe pruned categories if a LobePruner is
* provided.
* @param[in] material the material to process
* @param[in] lobePruner an instance of a LobePruner. These are usually singletons that
* accumulate pruned NodeDefs
* @param[in] textured is true if the full material is to be processed. When false, we will
* generate an untextured topo neutral material instead
*/
TopoNeutralGraph(
const MaterialX::ElementPtr& material,
const LobePruner::Ptr& lobePruner,
bool textured);
~TopoNeutralGraph();

MaterialX::NodeGraphPtr nodeGraph();
Expand Down
48 changes: 48 additions & 0 deletions test/lib/mayaUsd/utils/test_ShaderGenUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,51 @@ TEST(ShaderGenUtils, lobePruner)
optimizedNodeId = lobePruner->getOptimizedNodeId(usdNode);
ASSERT_TRUE(optimizedNodeId.IsEmpty());
}

TEST(ShaderGenUtils, lobePrunedTopoGraph)
{
namespace sgu = MaterialXMaya::ShaderGenUtil;

auto testPath = mx::FilePath(MATERIALX_TEST_DATA);

auto library = mx::createDocument();
ASSERT_TRUE(library != nullptr);
auto searchPath = PXR_NS::HdMtlxSearchPaths();
mx::loadLibraries({}, searchPath, library);

auto doc = mx::createDocument();
doc->importLibrary(library);

auto lobePruner = sgu::LobePruner::create();
lobePruner->setLibrary(doc);

const mx::XmlReadOptions readOptions;
mx::readFromXmlFile(doc, testPath / "MultiConnect1_topo.mtlx", mx::EMPTY_STRING, &readOptions);

const auto originalCategory = doc->getNode("N1")->getCategory();

auto topoNetwork
= MaterialXMaya::ShaderGenUtil::TopoNeutralGraph(doc->getNode("N0"), lobePruner, false);

// In thory, we should have an empty NodeGraph since we are in untextured mode:
ASSERT_TRUE(topoNetwork.getNodeGraph()->getNodes().empty());

// Should have only 2 nodes:
ASSERT_EQ(topoNetwork.getDocument()->getNodes().size(), 2);

// Surface should be optimized and fully unconnected:
const auto surface = topoNetwork.getDocument()->getNode("N1");

const auto surfaceCategory = surface->getCategory();

// Should begin with standard_surface
ASSERT_TRUE(surfaceCategory.rfind(originalCategory, 0) == 0);

// But have a LobePruner optimization:
ASSERT_TRUE(surfaceCategory.size() > originalCategory.size());

// Which should be in the library of the LobePruner:
topoNetwork.getDocument()->importLibrary(doc);
const auto optNodeDef = surface->getNodeDef();
ASSERT_TRUE(optNodeDef != nullptr);
}
Loading