diff --git a/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx b/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx
new file mode 100644
index 0000000000..4fbf6d12d9
--- /dev/null
+++ b/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp
index 7aa0b2c804..ec5e48d4ec 100644
--- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp
+++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp
@@ -10,7 +10,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -31,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -172,8 +172,8 @@ GlslShaderGenerator::GlslShaderGenerator() :
//
registerImplementation("IM_bitangent_vector3_" + GlslShaderGenerator::TARGET, BitangentNodeGlsl::create);
//
- registerImplementation("IM_texcoord_vector2_" + GlslShaderGenerator::TARGET, TexCoordNodeGlsl::create);
- registerImplementation("IM_texcoord_vector3_" + GlslShaderGenerator::TARGET, TexCoordNodeGlsl::create);
+ registerImplementation("IM_texcoord_vector2_" + GlslShaderGenerator::TARGET, HwTexCoordNode::create);
+ registerImplementation("IM_texcoord_vector3_" + GlslShaderGenerator::TARGET, HwTexCoordNode::create);
//
registerImplementation("IM_geomcolor_float_" + GlslShaderGenerator::TARGET, GeomColorNodeGlsl::create);
registerImplementation("IM_geomcolor_color3_" + GlslShaderGenerator::TARGET, GeomColorNodeGlsl::create);
diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.h b/source/MaterialXGenGlsl/GlslShaderGenerator.h
index 4c33042b2a..acc8b0d6ee 100644
--- a/source/MaterialXGenGlsl/GlslShaderGenerator.h
+++ b/source/MaterialXGenGlsl/GlslShaderGenerator.h
@@ -45,7 +45,7 @@ class MX_GENGLSL_API GlslShaderGenerator : public HwShaderGenerator
ShaderNodeImplPtr getImplementation(const NodeDef& nodedef, GenContext& context) const override;
/// Determine the prefix of vertex data variables.
- virtual string getVertexDataPrefix(const VariableBlock& vertexData) const;
+ string getVertexDataPrefix(const VariableBlock& vertexData) const override;
public:
/// Unique identifier for this generator target
diff --git a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp
deleted file mode 100644
index 846c77f5b7..0000000000
--- a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright Contributors to the MaterialX Project
-// SPDX-License-Identifier: Apache-2.0
-//
-
-#include
-
-#include
-
-MATERIALX_NAMESPACE_BEGIN
-
-ShaderNodeImplPtr TexCoordNodeGlsl::create()
-{
- return std::make_shared();
-}
-
-void TexCoordNodeGlsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const
-{
- const ShaderOutput* output = node.getOutput();
- const ShaderInput* indexInput = node.getInput(INDEX);
- const string index = indexInput ? indexInput->getValue()->getValueString() : "0";
-
- ShaderStage& vs = shader.getStage(Stage::VERTEX);
- ShaderStage& ps = shader.getStage(Stage::PIXEL);
-
- addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs);
- addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps);
-}
-
-void TexCoordNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
-{
- const GlslShaderGenerator& shadergen = static_cast(context.getShaderGenerator());
-
- const ShaderInput* indexInput = node.getInput(INDEX);
- const string index = indexInput ? indexInput->getValue()->getValueString() : "0";
- const string variable = HW::T_TEXCOORD + "_" + index;
-
- DEFINE_SHADER_STAGE(stage, Stage::VERTEX)
- {
- VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA);
- const string prefix = shadergen.getVertexDataPrefix(vertexData);
- ShaderPort* texcoord = vertexData[variable];
- if (!texcoord->isEmitted())
- {
- shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage);
- texcoord->setEmitted();
- }
- }
-
- DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
- {
- VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA);
- const string prefix = shadergen.getVertexDataPrefix(vertexData);
- ShaderPort* texcoord = vertexData[variable];
- shadergen.emitLineBegin(stage);
- shadergen.emitOutput(node.getOutput(), true, false, context, stage);
- shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage);
- shadergen.emitLineEnd(stage);
- }
-}
-
-MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp
index 2876bb504f..ea3fb7112d 100644
--- a/source/MaterialXGenMsl/MslShaderGenerator.cpp
+++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp
@@ -10,7 +10,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -31,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -176,8 +176,8 @@ MslShaderGenerator::MslShaderGenerator() :
//
registerImplementation("IM_bitangent_vector3_" + MslShaderGenerator::TARGET, BitangentNodeMsl::create);
//
- registerImplementation("IM_texcoord_vector2_" + MslShaderGenerator::TARGET, TexCoordNodeMsl::create);
- registerImplementation("IM_texcoord_vector3_" + MslShaderGenerator::TARGET, TexCoordNodeMsl::create);
+ registerImplementation("IM_texcoord_vector2_" + MslShaderGenerator::TARGET, HwTexCoordNode::create);
+ registerImplementation("IM_texcoord_vector3_" + MslShaderGenerator::TARGET, HwTexCoordNode::create);
//
registerImplementation("IM_geomcolor_float_" + MslShaderGenerator::TARGET, GeomColorNodeMsl::create);
registerImplementation("IM_geomcolor_color3_" + MslShaderGenerator::TARGET, GeomColorNodeMsl::create);
diff --git a/source/MaterialXGenMsl/MslShaderGenerator.h b/source/MaterialXGenMsl/MslShaderGenerator.h
index ac1d2e29c8..21817db735 100644
--- a/source/MaterialXGenMsl/MslShaderGenerator.h
+++ b/source/MaterialXGenMsl/MslShaderGenerator.h
@@ -48,7 +48,7 @@ class MX_GENMSL_API MslShaderGenerator : public HwShaderGenerator
ShaderNodeImplPtr getImplementation(const NodeDef& nodedef, GenContext& context) const override;
/// Determine the prefix of vertex data variables.
- virtual string getVertexDataPrefix(const VariableBlock& vertexData) const;
+ string getVertexDataPrefix(const VariableBlock& vertexData) const override;
public:
/// Unique identifier for this generator target
diff --git a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp
deleted file mode 100644
index a88152eb82..0000000000
--- a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright Contributors to the MaterialX Project
-// SPDX-License-Identifier: Apache-2.0
-//
-
-#include
-
-#include
-
-MATERIALX_NAMESPACE_BEGIN
-
-ShaderNodeImplPtr TexCoordNodeMsl::create()
-{
- return std::make_shared();
-}
-
-void TexCoordNodeMsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const
-{
- const ShaderOutput* output = node.getOutput();
- const ShaderInput* indexInput = node.getInput(INDEX);
- const string index = indexInput ? indexInput->getValue()->getValueString() : "0";
-
- ShaderStage& vs = shader.getStage(Stage::VERTEX);
- ShaderStage& ps = shader.getStage(Stage::PIXEL);
-
- addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs);
- addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps);
-}
-
-void TexCoordNodeMsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
-{
- const MslShaderGenerator& shadergen = static_cast(context.getShaderGenerator());
-
- const ShaderInput* indexInput = node.getInput(INDEX);
- const string index = indexInput ? indexInput->getValue()->getValueString() : "0";
- const string variable = HW::T_TEXCOORD + "_" + index;
-
- DEFINE_SHADER_STAGE(stage, Stage::VERTEX)
- {
- VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA);
- const string prefix = shadergen.getVertexDataPrefix(vertexData);
- ShaderPort* texcoord = vertexData[variable];
- if (!texcoord->isEmitted())
- {
- shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage);
- texcoord->setEmitted();
- }
- }
-
- DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
- {
- VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA);
- const string prefix = shadergen.getVertexDataPrefix(vertexData);
- ShaderPort* texcoord = vertexData[variable];
- shadergen.emitLineBegin(stage);
- shadergen.emitOutput(node.getOutput(), true, false, context, stage);
- shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage);
- shadergen.emitLineEnd(stage);
- }
-}
-
-MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h b/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h
deleted file mode 100644
index 6c227cc63b..0000000000
--- a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright Contributors to the MaterialX Project
-// SPDX-License-Identifier: Apache-2.0
-//
-
-#ifndef MATERIALX_TEXCOORDNODEMSL_H
-#define MATERIALX_TEXCOORDNODEMSL_H
-
-#include
-
-MATERIALX_NAMESPACE_BEGIN
-
-/// TexCoord node implementation for MSL
-class MX_GENMSL_API TexCoordNodeMsl : public MslImplementation
-{
- public:
- static ShaderNodeImplPtr create();
-
- void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override;
-
- void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override;
-};
-
-MATERIALX_NAMESPACE_END
-
-#endif
diff --git a/source/MaterialXGenShader/HwShaderGenerator.h b/source/MaterialXGenShader/HwShaderGenerator.h
index 66d60dc68a..bba572c631 100644
--- a/source/MaterialXGenShader/HwShaderGenerator.h
+++ b/source/MaterialXGenShader/HwShaderGenerator.h
@@ -306,6 +306,9 @@ class MX_GENSHADER_API HwShaderGenerator : public ShaderGenerator
/// Unbind all light shaders previously bound.
static void unbindLightShaders(GenContext& context);
+ /// Determine the prefix of vertex data variables.
+ virtual string getVertexDataPrefix(const VariableBlock& vertexData) const = 0;
+
/// Types of closure contexts for HW.
enum ClosureContextType
{
diff --git a/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp
new file mode 100644
index 0000000000..3aa84400df
--- /dev/null
+++ b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright Contributors to the MaterialX Project
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include
+#include
+#include
+
+MATERIALX_NAMESPACE_BEGIN
+
+string HwTexCoordNode::INDEX = "index";
+
+ShaderNodeImplPtr HwTexCoordNode::create()
+{
+ return std::make_shared();
+}
+
+void HwTexCoordNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const
+{
+ const ShaderOutput* output = node.getOutput();
+ const string index = getIndex(node);
+
+ ShaderStage& vs = shader.getStage(Stage::VERTEX);
+ ShaderStage& ps = shader.getStage(Stage::PIXEL);
+
+ addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs, true);
+ addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps, true);
+}
+
+void HwTexCoordNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
+{
+ const HwShaderGenerator& shadergen = static_cast(context.getShaderGenerator());
+
+ const string index = getIndex(node);
+ const string variable = HW::T_TEXCOORD + "_" + index;
+ const ShaderOutput* output = node.getOutput();
+
+ DEFINE_SHADER_STAGE(stage, Stage::VERTEX)
+ {
+ VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA);
+ const string prefix = shadergen.getVertexDataPrefix(vertexData);
+ ShaderPort* texcoord = vertexData[variable];
+ if (!texcoord->isEmitted())
+ {
+ shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage);
+ texcoord->setEmitted();
+ }
+ }
+
+ DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
+ {
+ VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA);
+ const string prefix = shadergen.getVertexDataPrefix(vertexData);
+ ShaderPort* texcoord = vertexData[variable];
+ shadergen.emitLineBegin(stage);
+ shadergen.emitOutput(output, true, false, context, stage);
+
+ // Extract the requested number of components from the texture coordinates (which may be a
+ // larger datatype than the requested number of texture coordinates, if several texture
+ // coordinate nodes with different width coexist).
+ string suffix = EMPTY_STRING;
+ if (output->getType() == Type::VECTOR2)
+ {
+ suffix = ".xy";
+ }
+ else if (output->getType() == Type::VECTOR3)
+ {
+ suffix = ".xyz";
+ }
+
+ shadergen.emitString(" = " + prefix + texcoord->getVariable() + suffix, stage);
+ shadergen.emitLineEnd(stage);
+ }
+}
+
+string HwTexCoordNode::getIndex(const ShaderNode& node) const
+{
+ const ShaderInput* input = node.getInput(INDEX);
+ return input ? input->getValue()->getValueString() : "0";
+}
+
+MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h b/source/MaterialXGenShader/Nodes/HwTexCoordNode.h
similarity index 55%
rename from source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h
rename to source/MaterialXGenShader/Nodes/HwTexCoordNode.h
index c15a86fd9c..9aae3d18ce 100644
--- a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h
+++ b/source/MaterialXGenShader/Nodes/HwTexCoordNode.h
@@ -3,15 +3,15 @@
// SPDX-License-Identifier: Apache-2.0
//
-#ifndef MATERIALX_TEXCOORDNODEGLSL_H
-#define MATERIALX_TEXCOORDNODEGLSL_H
+#ifndef MATERIALX_HWTEXCOORDNODE_H
+#define MATERIALX_HWTEXCOORDNODE_H
-#include
+#include
MATERIALX_NAMESPACE_BEGIN
-/// TexCoord node implementation for GLSL
-class MX_GENGLSL_API TexCoordNodeGlsl : public GlslImplementation
+/// Generic texture coordinate node for hardware languages
+class MX_GENSHADER_API HwTexCoordNode : public ShaderNodeImpl
{
public:
static ShaderNodeImplPtr create();
@@ -19,6 +19,11 @@ class MX_GENGLSL_API TexCoordNodeGlsl : public GlslImplementation
void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override;
void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override;
+
+ protected:
+ virtual string getIndex(const ShaderNode& node) const;
+
+ static string INDEX;
};
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenShader/ShaderStage.cpp b/source/MaterialXGenShader/ShaderStage.cpp
index 822f3c9664..b5387bcb94 100644
--- a/source/MaterialXGenShader/ShaderStage.cpp
+++ b/source/MaterialXGenShader/ShaderStage.cpp
@@ -65,11 +65,26 @@ ShaderPort* VariableBlock::find(const ShaderPortPredicate& predicate)
return nullptr;
}
-ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePtr value)
+ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePtr value, bool shouldWiden)
{
auto it = _variableMap.find(name);
if (it != _variableMap.end())
{
+ if (shouldWiden)
+ {
+ // Automatically try to widen the type of the shader port if the requested type differs from
+ // the existing port's type.
+ if (it->second->getType()->getSize() < type->getSize())
+ {
+ it->second->setType(type);
+ }
+ }
+ else if (type != it->second->getType())
+ {
+ throw ExceptionShaderGenError("Trying to add shader port '" + name + "' with type '" +
+ type->getName() + "', but existing shader port with type '" +
+ it->second->getType()->getName() + "' was found");
+ }
return it->second.get();
}
diff --git a/source/MaterialXGenShader/ShaderStage.h b/source/MaterialXGenShader/ShaderStage.h
index 71004f8e52..a6a5cec0b8 100644
--- a/source/MaterialXGenShader/ShaderStage.h
+++ b/source/MaterialXGenShader/ShaderStage.h
@@ -113,7 +113,14 @@ class MX_GENSHADER_API VariableBlock
ShaderPort* find(const ShaderPortPredicate& predicate);
/// Add a new shader port to this block.
- ShaderPort* add(const TypeDesc* type, const string& name, ValuePtr value = nullptr);
+ /// @param type The desired shader port type
+ /// @param name The shader port name
+ /// @param value The value to attach to the shader port
+ /// @param shouldWiden When false, an exception is thrown if the type of the existing port with
+ /// the same name does not match the requested type. When true, the types can mismatch, and the
+ /// type of any existing port is widened to match the requested type when necessary.
+ /// @return A new shader port, or a pre-existing shader port with the same name.
+ ShaderPort* add(const TypeDesc* type, const string& name, ValuePtr value = nullptr, bool shouldWiden = false);
/// Add an existing shader port to this block.
void add(ShaderPortPtr port);
@@ -339,20 +346,22 @@ inline ShaderPort* addStageUniform(const string& block,
inline ShaderPort* addStageInput(const string& block,
const TypeDesc* type,
const string& name,
- ShaderStage& stage)
+ ShaderStage& stage,
+ bool shouldWiden = false)
{
VariableBlock& inputs = stage.getInputBlock(block);
- return inputs.add(type, name);
+ return inputs.add(type, name, {}, shouldWiden);
}
/// Utility function for adding a new shader port to an output block.
inline ShaderPort* addStageOutput(const string& block,
const TypeDesc* type,
const string& name,
- ShaderStage& stage)
+ ShaderStage& stage,
+ bool shouldWiden = false)
{
VariableBlock& outputs = stage.getOutputBlock(block);
- return outputs.add(type, name);
+ return outputs.add(type, name, {}, shouldWiden);
}
/// Utility function for adding a connector block between stages.
@@ -370,10 +379,11 @@ inline void addStageConnector(const string& block,
const TypeDesc* type,
const string& name,
ShaderStage& from,
- ShaderStage& to)
+ ShaderStage& to,
+ bool shouldWiden = false)
{
- addStageOutput(block, type, name, from);
- addStageInput(block, type, name, to);
+ addStageOutput(block, type, name, from, shouldWiden);
+ addStageInput(block, type, name, to, shouldWiden);
}
MATERIALX_NAMESPACE_END