Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
<?xml version="1.0"?>
<materialx version="1.39" colorspace="lin_rec709">

<UsdPrimvarReader name="read_st" type="vector2">
<input name="varname" type="string" value="st" />
</UsdPrimvarReader>
<UsdUVTexture name="image_color" type="multioutput">
<input name="file" type="filename" value="../../../Images/brass_color.jpg" colorspace="srgb_texture" />
<input name="st" type="vector2" nodename="read_st" />
</UsdUVTexture>
<UsdUVTexture name="image_roughness" type="multioutput">
<input name="file" type="filename" value="../../../Images/brass_roughness.jpg" />
<input name="st" type="vector2" nodename="read_st" />
</UsdUVTexture>
<UsdPreviewSurface name="SR_brass" type="surfaceshader">
<input name="diffuseColor" type="color3" nodename="image_color" output="rgb" />
<input name="metallic" type="float" value="1" />
<input name="roughness" type="float" nodename="image_roughness" output="r" />
</UsdPreviewSurface>
<surfacematerial name="USD_Brass" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="SR_brass" />
</surfacematerial>

<nodegraph name="NG_brass1" fileprefix="../../../Images/">
<tiledimage name="image_color" type="color3">
<input name="file" type="filename" value="brass_color.jpg" colorspace="srgb_texture" />
Expand Down
1 change: 0 additions & 1 deletion source/MaterialXGenHw/HwImplementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ MATERIALX_NAMESPACE_BEGIN

const string HwImplementation::SPACE = "space";
const string HwImplementation::INDEX = "index";
const string HwImplementation::GEOMPROP = "geomprop";

namespace
{
Expand Down
1 change: 0 additions & 1 deletion source/MaterialXGenHw/HwImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class MX_GENHW_API HwImplementation : public ShaderNodeImpl
/// Internal string constants
static const string SPACE;
static const string INDEX;
static const string GEOMPROP;
};

MATERIALX_NAMESPACE_END
Expand Down
78 changes: 69 additions & 9 deletions source/MaterialXGenHw/Nodes/HwGeomPropValueNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,77 @@

MATERIALX_NAMESPACE_BEGIN

static const string GEOMPROP = "geomprop";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Think you can use GeomProp::CATEGORY


ShaderNodeImplPtr HwGeomPropValueNode::create()
{
return std::make_shared<HwGeomPropValueNode>();
}

void HwGeomPropValueNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const
// Find the ShaderInput that contains the actual name of the geomprop to read
static const ShaderInput* getGeomPropValueInput(const ShaderNode& node, const GenContext& context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Niklas can speak better than I on threading but I don't think we should add any static methods in code generation. Maybe add this as a method on ShaderNode instead ?

{
// We should always have the "geomprop" input locally on this node
const ShaderInput* geomPropInput = node.getInput(GEOMPROP);
if (!geomPropInput)
{
throw ExceptionShaderGenError("No 'geomprop' input found on geompropvalue node '" + node.getName() + "'.");
}

// Depth into the compound instance stack, measured from the innermost
// instance. Incremented each time we cross a graph boundary so that nested
// compounds resolve to the correct enclosing instance.
size_t depth = 0;

while (geomPropInput)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checking that this will work if this has to read through a functional nodegraph (i.e. the graph connection is a nodedef implementation). I think it does since shader gen embeds implementation graphs.

{
// If it has a local value set, then we've found the ShaderInput and can return that
ConstValuePtr value = geomPropInput->getValue();
if (value)
{
return geomPropInput;
}

// If we don't have a local value, then we may have an incoming connection from a containing NodeGraph
// Note : the "geomprop" input on the base node is "uniform" so it cannot be driven by the output from
// another node.
const ShaderOutput* upstreamPort = geomPropInput->getConnection();
if (!upstreamPort)
{
return nullptr;
}

const ShaderNode* upstreamNode = upstreamPort->getNode();
if (!upstreamNode || !upstreamNode->isAGraph())
{
return nullptr;
}

// We've reached a graph input socket. Step out to the matching compound
// instance, walking the instance stack outward in tandem with the graph
// boundary we just crossed, so that nested compounds resolve to the
// correct instance rather than always the innermost one.
const ShaderNode* compoundInstance = context.getCompoundInstanceNode(depth++);
if (!compoundInstance)
{
return nullptr;
}

// Consider the input on the compound instance to be the new potential
// source for the value of "geomprop". The next iteration either finds a
// value here or continues climbing.
geomPropInput = compoundInstance->getInput(upstreamPort->getName());
}

return nullptr;
}

void HwGeomPropValueNode::createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const
{
const ShaderInput* geomPropInput = getGeomPropValueInput(node, context);
if (!geomPropInput || !geomPropInput->getValue())
{
throw ExceptionShaderGenError("No 'geomprop' parameter found on geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
throw ExceptionShaderGenError("No 'geomprop' value found for geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
}
const string geomProp = geomPropInput->getValue()->getValueString();
const ShaderOutput* output = node.getOutput();
Expand All @@ -39,10 +99,10 @@ void HwGeomPropValueNode::emitFunctionCall(const ShaderNode& node, GenContext& c
{
const HwShaderGenerator& shadergen = static_cast<const HwShaderGenerator&>(context.getShaderGenerator());

const ShaderInput* geomPropInput = node.getInput(GEOMPROP);
const ShaderInput* geomPropInput = getGeomPropValueInput(node, context);
if (!geomPropInput)
{
throw ExceptionShaderGenError("No 'geomprop' parameter found on geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
throw ExceptionShaderGenError("No 'geomprop' value found for geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
}
const string geomname = geomPropInput->getValue()->getValueString();
const string variable = HW::T_IN_GEOMPROP + "_" + geomname;
Expand Down Expand Up @@ -76,12 +136,12 @@ ShaderNodeImplPtr HwGeomPropValueNodeAsUniform::create()
return std::make_shared<HwGeomPropValueNodeAsUniform>();
}

void HwGeomPropValueNodeAsUniform::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const
void HwGeomPropValueNodeAsUniform::createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const
{
const ShaderInput* geomPropInput = node.getInput(GEOMPROP);
const ShaderInput* geomPropInput = getGeomPropValueInput(node, context);
if (!geomPropInput || !geomPropInput->getValue())
{
throw ExceptionShaderGenError("No 'geomprop' parameter found on geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
throw ExceptionShaderGenError("No 'geomprop' value found for geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
}
const string geomProp = geomPropInput->getValue()->getValueString();
ShaderStage& ps = shader.getStage(Stage::PIXEL);
Expand All @@ -94,10 +154,10 @@ void HwGeomPropValueNodeAsUniform::emitFunctionCall(const ShaderNode& node, GenC
DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
{
const ShaderGenerator& shadergen = context.getShaderGenerator();
const ShaderInput* geomPropInput = node.getInput(GEOMPROP);
const ShaderInput* geomPropInput = getGeomPropValueInput(node, context);
if (!geomPropInput)
{
throw ExceptionShaderGenError("No 'geomprop' parameter found on geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
throw ExceptionShaderGenError("No 'geomprop' value found for geompropvalue node '" + node.getName() + "'. Don't know what property to bind");
}
const string attrName = geomPropInput->getValue()->getValueString();
shadergen.emitLineBegin(stage);
Expand Down
45 changes: 45 additions & 0 deletions source/MaterialXGenShader/GenContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ class MX_GENSHADER_API GenContext
return _parentNodes;
}

/// Push a compound instance node onto the stack.
void pushCompoundInstanceNode(const ShaderNode* node)
{
_compoundInstanceNodes.push_back(node);
}

/// Pop the current compound instance node from the stack.
void popCompoundInstanceNode()
{
_compoundInstanceNodes.pop_back();
}

/// Return the compound instance node at the given depth from the
/// innermost instance (depth 0), or nullptr if the depth is out of range.
const ShaderNode* getCompoundInstanceNode(size_t depth = 0) const
{
return depth < _compoundInstanceNodes.size()
? _compoundInstanceNodes[_compoundInstanceNodes.size() - 1 - depth]
: nullptr;
}

/// Add user data to the context to make it
/// available during shader generator.
void pushUserData(const string& name, GenUserDataPtr data)
Expand Down Expand Up @@ -218,6 +239,7 @@ class MX_GENSHADER_API GenContext
std::unordered_map<const ShaderOutput*, string> _outputSuffix;

vector<ConstNodePtr> _parentNodes;
vector<const ShaderNode*> _compoundInstanceNodes;

ApplicationVariableHandler _applicationVariableHandler;
};
Expand All @@ -237,6 +259,29 @@ class MX_GENSHADER_API ScopedSetVariableName
string _oldName;
};

/// A RAII class for tracking the active compound instance node on the
/// GenContext stack, ensuring the node is popped even if shader generation
/// throws while the compound is being processed.
class MX_GENSHADER_API ScopedSetCompoundInstanceNode
{
public:
/// Constructor pushing a compound instance node onto the context stack.
ScopedSetCompoundInstanceNode(GenContext& context, const ShaderNode* node) :
_context(context)
{
_context.pushCompoundInstanceNode(node);
}

/// Destructor popping the compound instance node from the context stack.
~ScopedSetCompoundInstanceNode()
{
_context.popCompoundInstanceNode();
}

private:
GenContext& _context;
};

MATERIALX_NAMESPACE_END

#endif // MATERIALX_GENCONTEXT_H
7 changes: 6 additions & 1 deletion source/MaterialXGenShader/Nodes/CompoundNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ void CompoundNode::initialize(const InterfaceElement& element, GenContext& conte
_hash = std::hash<string>{}(_functionName);
}

void CompoundNode::createVariables(const ShaderNode&, GenContext& context, Shader& shader) const
void CompoundNode::createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const
{
ScopedSetCompoundInstanceNode scopedInstance(context, &node);

// Gather shader inputs from all child nodes
for (const ShaderNode* childNode : _rootGraph->getNodes())
{
Expand All @@ -74,6 +76,8 @@ void CompoundNode::emitFunctionDefinition(const ShaderNode& node, GenContext& co
{
const ShaderGenerator& shadergen = context.getShaderGenerator();

ScopedSetCompoundInstanceNode scopedInstance(context, &node);

// Emit functions for all child nodes
shadergen.emitFunctionDefinitions(*_rootGraph, context, stage);

Expand Down Expand Up @@ -164,6 +168,7 @@ void CompoundNode::emitFunctionCall(const ShaderNode& node, GenContext& context,
DEFINE_SHADER_STAGE(stage, Stage::VERTEX)
{
// Emit function calls for all child nodes to the vertex shader stage
ScopedSetCompoundInstanceNode scopedInstance(context, &node);
shadergen.emitFunctionCalls(*_rootGraph, context, stage);
}

Expand Down
1 change: 1 addition & 0 deletions source/MaterialXRender/CgltfLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ bool CgltfLoader::load(const FilePath& filePath, MeshList& meshList, bool texcoo
texcoordStream = mesh->generateTextureCoordinates(positionStream);
mesh->addStream(texcoordStream);
}
mesh->addStreamAlias("i_" + MeshStream::GEOMETRY_PROPERTY_ATTRIBUTE + "_st", texcoordStream->getName());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This assumes a assumption on both the code gen and geometry loader side to "know" about adding "_st" postfix alias. Would it be possible to reflect this mapping within code generation so renderers can pull the appropriate given name or alias name ?

if (!vec4TangentStream)
{
MeshStreamPtr tangentStream = mesh->generateTangents(positionStream, normalStream, texcoordStream);
Expand Down
23 changes: 22 additions & 1 deletion source/MaterialXRender/Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ class MX_RENDER_API Mesh
return _sourceUri;
}

/// Get a mesh stream by name
/// Get a mesh stream by name. If no stream matches directly, the name is
/// resolved through any registered stream aliases.
/// @param name Name of stream
/// @return Reference to a mesh stream if found
MeshStreamPtr getStream(const string& name) const
Expand All @@ -285,9 +286,28 @@ class MX_RENDER_API Mesh
return stream;
}
}
auto it = _streamAliases.find(name);
if (it != _streamAliases.end())
{
for (const auto& stream : _streams)
{
if (stream->getName() == it->second)
{
return stream;
}
}
}
return MeshStreamPtr();
}

/// Register an alias so that getStream(alias) resolves to the stream
/// named target. Used to expose a single underlying stream under multiple
/// shader-input names (e.g. mapping the USD "st" primvar to UV0).
void addStreamAlias(const string& alias, const string& target)
{
_streamAliases[alias] = target;
}

/// Get a mesh stream by type and index
/// @param type Type of stream
/// @param index Index of stream
Expand Down Expand Up @@ -440,6 +460,7 @@ class MX_RENDER_API Mesh
float _sphereRadius;

MeshStreamList _streams;
std::unordered_map<string, string> _streamAliases;
size_t _vertexCount;
vector<MeshPartitionPtr> _partitions;
};
Expand Down
1 change: 1 addition & 0 deletions source/MaterialXRender/TinyObjLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ bool TinyObjLoader::load(const FilePath& filePath, MeshList& meshList, bool texc
texcoordStream = mesh->generateTextureCoordinates(positionStream);
}
mesh->addStream(texcoordStream);
mesh->addStreamAlias("i_" + MeshStream::GEOMETRY_PROPERTY_ATTRIBUTE + "_st", texcoordStream->getName());

MeshStreamPtr tangentStream = mesh->generateTangents(positionStream, normalStream, texcoordStream);
if (tangentStream)
Expand Down
Loading
Loading