Skip to content

Commit

Permalink
MDL 1.9 updates (AcademySoftwareFoundation#2102)
Browse files Browse the repository at this point in the history
add new version to GenMDL and remove uniform restriction from material IOR

Minor updates:
- improve MDL printing by adding named parameters
- handle 1-element mixes (basically scale) above layers
- improve blur and height to normal to return something meaningful (before totally broken)
- improve non-material outputs that can be rendered, e.g. float3x3 and float4x4
- preparations for MDL 1.10
- remove shader parameters from the public MDL material interface. backsurfaceshader and displacementshader showed up with default values only after recent upstream changes
  • Loading branch information
krohmerNV authored Nov 21, 2024
1 parent a368aac commit a3a7744
Show file tree
Hide file tree
Showing 14 changed files with 961 additions and 64 deletions.
6 changes: 3 additions & 3 deletions libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<materialx version="1.39">

<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genmdl" nodedef="ND_oren_nayar_diffuse_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_oren_nayar_diffuse_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}})" target="genmdl" />
<implementation name="IM_oren_nayar_diffuse_bsdf_genmdl" nodedef="ND_oren_nayar_diffuse_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_oren_nayar_diffuse_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}}, mxp_energy_compensation:{{energy_compensation}})" target="genmdl" />

<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genmdl" nodedef="ND_burley_diffuse_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_burley_diffuse_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}})" target="genmdl" />
Expand All @@ -11,13 +11,13 @@
<implementation name="IM_translucent_bsdf_genmdl" nodedef="ND_translucent_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_translucent_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_normal:{{normal}})" target="genmdl" />

<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genmdl" nodedef="ND_dielectric_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_dielectric_bsdf(mxp_weight:{{weight}}, mxp_tint:{{tint}}, mxp_ior:{{ior}}, mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}})" target="genmdl" />
<implementation name="IM_dielectric_bsdf_genmdl" nodedef="ND_dielectric_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_dielectric_bsdf(mxp_weight:{{weight}}, mxp_tint:{{tint}}, mxp_ior:{{ior}}, mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />

<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genmdl" nodedef="ND_conductor_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_conductor_bsdf(mxp_weight:{{weight}}, mxp_ior:{{ior}}, mxp_extinction:{{extinction}}, mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}})" target="genmdl" />

<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genmdl" nodedef="ND_generalized_schlick_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_bsdf(mxp_weight:{{weight}}, mxp_color0:{{color0}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}},mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}})" target="genmdl" />
<implementation name="IM_generalized_schlick_bsdf_genmdl" nodedef="ND_generalized_schlick_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_bsdf(mxp_weight:{{weight}}, mxp_color0:{{color0}}, mxp_color82:{{color82}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}},mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />

<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genmdl" nodedef="ND_subsurface_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_subsurface_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_radius:{{radius}}, mxp_anisotropy:{{anisotropy}}, mxp_normal:{{normal}})" target="genmdl" />
Expand Down
2 changes: 1 addition & 1 deletion libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@
<implementation name="IM_combine3_vector3_genmdl" nodedef="ND_combine3_vector3" target="genmdl" sourcecode="float3( {{in1}},{{in2}},{{in3}} )" />

<!-- <combine4> -->
<implementation name="IM_combine4_color4_genmdl" nodedef="ND_combine4_color4" target="genmdl" sourcecode="color4( {{in1}},{{in2}},{{in3}},{{in4}} )" />
<implementation name="IM_combine4_color4_genmdl" nodedef="ND_combine4_color4" target="genmdl" sourcecode="materialx::core::mk_color4( {{in1}},{{in2}},{{in3}},{{in4}} )" />
<implementation name="IM_combine4_vector4_genmdl" nodedef="ND_combine4_vector4" target="genmdl" sourcecode="float4( {{in1}},{{in2}},{{in3}},{{in4}} )" />

<!-- <creatematrix> -->
Expand Down
89 changes: 77 additions & 12 deletions source/MaterialXGenMdl/MdlShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ const string IMPORT_ALL = " import *";
const string MDL_VERSION_1_6 = "1.6";
const string MDL_VERSION_1_7 = "1.7";
const string MDL_VERSION_1_8 = "1.8";
const string MDL_VERSION_1_9 = "1.9";
const string MDL_VERSION_SUFFIX_1_6 = "1_6";
const string MDL_VERSION_SUFFIX_1_7 = "1_7";
const string MDL_VERSION_SUFFIX_1_8 = "1_8";
const string MDL_VERSION_SUFFIX_1_9 = "1_9";

} // anonymous namespace

Expand Down Expand Up @@ -191,6 +193,27 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G
emitLineBreak(stage);
}

// Emit shader inputs that have been filtered during printing of the public interface
const string uniformPrefix = _syntax->getUniformQualifier() + " ";
for (ShaderGraphInputSocket* inputSocket : graph.getInputSockets())
{
if (inputSocket->getConnections().size() &&
(inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER ||
inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE ||
inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL))
{
const string& qualifier = inputSocket->isUniform() || inputSocket->getType() == Type::FILENAME
? uniformPrefix
: EMPTY_STRING;
const string& type = _syntax->getTypeName(inputSocket->getType());

emitLineBegin(stage);
emitString(qualifier + type + " " + inputSocket->getVariable() + " = ", stage);
emitString(_syntax->getDefaultValue(inputSocket->getType(), true), stage);
emitLineEnd(stage, true);
}
}

// Emit all texturing nodes. These are inputs to any
// closure/shader nodes and need to be emitted first.
emitFunctionCalls(graph, context, stage, ShaderNode::Classification::TEXTURE);
Expand All @@ -215,6 +238,7 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G
const string result = getUpstreamResult(outputSocket, context);

const TypeDesc outputType = outputSocket->getType();
// Try to return some meaningful color in case the output is not a material
if (graph.hasClassification(ShaderNode::Classification::TEXTURE))
{
if (outputType == Type::DISPLACEMENTSHADER)
Expand All @@ -229,7 +253,25 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G
else
{
emitLine("float3 displacement__ = float3(0.0)", stage);
emitLine("color finalOutput__ = mk_color3(" + result + ")", stage);
std::string finalOutput = "mk_color3(0.0)";
if (outputType == Type::BOOLEAN)
finalOutput = result + " ? mk_color3(0.0, 1.0, 0.0) : mk_color3(1.0, 0.0, 0.0)";
else if (outputType == Type::INTEGER)
finalOutput = "mk_color3(" + result + " / 100)"; // arbitrary
else if (outputType == Type::FLOAT)
finalOutput = "mk_color3(" + result + ")";
else if (outputType == Type::VECTOR2)
finalOutput = "mk_color3(" + result + ".x, " + result + ".y, 0.0)";
else if (outputType == Type::VECTOR3)
finalOutput = "mk_color3(" + result + ")";
else if (outputType == Type::COLOR3)
finalOutput = result;
else if (outputType == Type::COLOR4)
finalOutput = result + ".rgb";
else if (outputType == Type::MATRIX33 || outputType == Type::MATRIX44)
finalOutput = "mk_color3(" + result + "[0][0], " + result + "[1][1], " + result + "[2][2])";

emitLine("color finalOutput__ = " + finalOutput, stage);
}

// End shader body
Expand Down Expand Up @@ -527,6 +569,13 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen
// and are editable by users.
if (inputSocket->getConnections().size() && graph->isEditable(*inputSocket))
{
if (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER ||
inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE ||
inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL)
{
continue;
}

inputs->add(inputSocket->getSelf());
}
}
Expand All @@ -537,7 +586,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen
outputs->add(outputSocket->getSelf());
}

// MDL does not allow varying data connected to transmission IOR.
// MDL does not allow varying data connected to transmission IOR until MDL 1.9.
// We must find all uses of transmission IOR and make sure we don't
// have a varying connection to it. If a varying connection is found
// we break that connection and revert to using default value on that
Expand All @@ -552,8 +601,14 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen
// this fix will disconnect the transmission IOR on the inside, but
// still support the connection to reflection IOR.
//
if (graph->hasClassification(ShaderNode::Classification::SHADER) ||
graph->hasClassification(ShaderNode::Classification::CLOSURE))
GenMdlOptions::MdlVersion version = getMdlVersion(context);
bool uniformIorRequired =
version == GenMdlOptions::MdlVersion::MDL_1_6 ||
version == GenMdlOptions::MdlVersion::MDL_1_7 ||
version == GenMdlOptions::MdlVersion::MDL_1_8;
if (uniformIorRequired && (
graph->hasClassification(ShaderNode::Classification::SHADER) ||
graph->hasClassification(ShaderNode::Classification::CLOSURE)))
{
// Find dependencies on transmission IOR.
std::set<ShaderGraph*> graphsWithIorDependency;
Expand Down Expand Up @@ -641,10 +696,15 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB
}
}

void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const
GenMdlOptions::MdlVersion MdlShaderGenerator::getMdlVersion(GenContext& context) const
{
GenMdlOptionsPtr options = context.getUserData<GenMdlOptions>(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY);
GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST;
return options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST;
}

void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const
{
GenMdlOptions::MdlVersion version = getMdlVersion(context);

emitLineBegin(stage);
emitString("mdl ", stage);
Expand All @@ -656,30 +716,35 @@ void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage&
case GenMdlOptions::MdlVersion::MDL_1_7:
emitString(MDL_VERSION_1_7, stage);
break;
case GenMdlOptions::MdlVersion::MDL_1_8:
emitString(MDL_VERSION_1_8, stage);
break;
default:
// GenMdlOptions::MdlVersion::MDL_1_8
// GenMdlOptions::MdlVersion::MDL_1_9
// GenMdlOptions::MdlVersion::MDL_LATEST
emitString(MDL_VERSION_1_8, stage);
emitString(MDL_VERSION_1_9, stage);
break;
}
emitLineEnd(stage, true);
}


const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& context) const
{
GenMdlOptionsPtr options = context.getUserData<GenMdlOptions>(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY);
GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST;
GenMdlOptions::MdlVersion version = getMdlVersion(context);

switch (version)
{
case GenMdlOptions::MdlVersion::MDL_1_6:
return MDL_VERSION_SUFFIX_1_6;
case GenMdlOptions::MdlVersion::MDL_1_7:
return MDL_VERSION_SUFFIX_1_7;
case GenMdlOptions::MdlVersion::MDL_1_8:
return MDL_VERSION_SUFFIX_1_8;
default:
// GenMdlOptions::MdlVersion::MDL_1_8
// GenMdlOptions::MdlVersion::MDL_1_9
// GenMdlOptions::MdlVersion::MDL_LATEST
return MDL_VERSION_SUFFIX_1_8;
return MDL_VERSION_SUFFIX_1_9;
}
}

Expand Down
9 changes: 7 additions & 2 deletions source/MaterialXGenMdl/MdlShaderGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class MX_GENMDL_API GenMdlOptions : public GenUserData
MDL_1_6,
MDL_1_7,
MDL_1_8,
MDL_LATEST = MDL_1_8
MDL_1_9,
MDL_LATEST = MDL_1_9
};

/// Create MDL code generator options with default values.
Expand Down Expand Up @@ -76,7 +77,11 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator
/// Map of code snippets for geomprops in MDL.
static const std::unordered_map<string, string> GEOMPROP_DEFINITIONS;

/// Add the MDL file header containing the version number of the generated module..
/// Get the selected MDL target language version number from the context option.
/// If not set, the latest version supported by GenMdl is returned.
GenMdlOptions::MdlVersion getMdlVersion(GenContext& context) const;

/// Add the MDL file header containing the version number of the generated module.
void emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const;

/// Add the version number suffix appended to MDL modules that use versions.
Expand Down
45 changes: 45 additions & 0 deletions source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ MATERIALX_NAMESPACE_BEGIN

const string StringConstantsMdl::TOP = "top";
const string StringConstantsMdl::BASE = "base";
const string StringConstantsMdl::FG = "fg";
const string StringConstantsMdl::BG = "bg";
const string StringConstantsMdl::MIX = "mix";
const string StringConstantsMdl::TOP_WEIGHT = "top_weight";

ShaderNodeImplPtr ClosureLayerNodeMdl::create()
{
Expand Down Expand Up @@ -101,6 +105,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext&

// Transport the base bsdf further than one layer
ShaderNode* baseReceiverNode = top;
ShaderNode* mixTopWeightNode = nullptr;
while (true)
{
// If the top node is again a layer, we don't want to override the base
Expand All @@ -111,6 +116,26 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext&
}
else
{
// TODO is there a more efficient way to check if the node is a mix_bsdf?
std::string name = top->getImplementation().getName();
if (name == "IM_mix_bsdf_genmdl")
{
// handle one special case: the top node is a mix where either fg or bg is empty
// so basically a scale factor
ShaderOutput* fgOutput = top->getInput(StringConstantsMdl::FG)->getConnection();
ShaderOutput* bgOutput = top->getInput(StringConstantsMdl::BG)->getConnection();
ShaderOutput* mixOutput = top->getInput(StringConstantsMdl::MIX)->getConnection();
ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr;
ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr;
ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr;
if ((fg && !bg) || (!fg && bg))
{
baseReceiverNode = fg ? fg : bg; // take the node that is valid
top = baseReceiverNode;
mixTopWeightNode = mix;
}
break;
}
// we stop at elemental bsdfs
// TODO handle mix, add, and multiply
break;
Expand Down Expand Up @@ -150,6 +175,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext&
// base BSDF connection and output variable name from the
// layer operator itself.
topNodeBaseInput->makeConnection(base->getOutput());
if (mixTopWeightNode)
{
ShaderInput* topNodeTopWeightInput = baseReceiverNode->getInput(StringConstantsMdl::TOP_WEIGHT);
topNodeTopWeightInput->makeConnection(mixTopWeightNode->getOutput());
}
ScopedSetVariableName setVariable(output->getVariable(), top->getOutput());

// Make the call.
Expand All @@ -171,6 +201,21 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons
{
// Add the input to hold base layer BSDF.
node.addInput(StringConstantsMdl::BASE, Type::BSDF);

// Set the top level weight default to 1.0
ShaderInput* topWeightNode = node.addInput(StringConstantsMdl::TOP_WEIGHT, Type::FLOAT);
ValuePtr value = TypedValue<float>::createValue(1.0f);
topWeightNode->setValue(value);
}

bool LayerableNodeMdl::isEditable(const ShaderInput& input) const
{
if (input.getName() == StringConstantsMdl::BASE ||
input.getName() == StringConstantsMdl::TOP_WEIGHT)
{
return false;
}
return BASE::isEditable(input);
}

MATERIALX_NAMESPACE_END
7 changes: 7 additions & 0 deletions source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class MX_GENMDL_API StringConstantsMdl
/// String constants
static const string TOP; ///< layer parameter name of the top component
static const string BASE; ///< layer parameter name of the base component
static const string FG; ///< mix parameter name of the foreground
static const string BG; ///< mix parameter name of the background
static const string MIX; ///< mix parameter name of the amount
static const string TOP_WEIGHT; ///< mix amount forwarded into layer top component
};

/// Closure layer node implementation for MDL.
Expand All @@ -40,11 +44,14 @@ class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl
/// Note, not all elemental bsdfs support this kind of transformation.
class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl
{
using BASE = SourceCodeNodeMdl;

public:
virtual ~LayerableNodeMdl() = default;
static ShaderNodeImplPtr create();

void addInputs(ShaderNode& node, GenContext&) const override;
bool isEditable(const ShaderInput& input) const override;
};

MATERIALX_NAMESPACE_END
Expand Down
Loading

0 comments on commit a3a7744

Please sign in to comment.