Skip to content

Commit

Permalink
Update MDL code generator to support MDL 1.7 (AcademySoftwareFoundati…
Browse files Browse the repository at this point in the history
…on#1273)

- changed the sheen implementation to match OSL as close as possible
- completed the mix, add, and multiply functions for BSDFs, EDFs, and VDFs
- add MDL implementation for mix of surfaceshader, volumeshader, and displacementshader
- fixed empty resource paths that showed MaterialX fileprefixes
- handled relative resources, but encourage to use `flattenFilenames` on the document before generating MDL in order to have full application control on resource paths
  • Loading branch information
krohmerNV authored Mar 10, 2023
1 parent 6b31a80 commit 4104569
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 94 deletions.
11 changes: 7 additions & 4 deletions libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,17 @@
<implementation name="IM_mix_vdf_genmdl" nodedef="ND_mix_vdf" sourcecode="mx::pbrlib::mx_mix_vdf(mxp_fg:{{fg}}, mxp_bg:{{bg}}, mxp_mix:{{mix}})" target="genmdl" />

<!-- <add> -->
<implementation name="IM_add_bsdf_genmdl" nodedef="ND_add_bsdf" sourcecode="{{in1}}" target="genmdl" /> <!-- TODO: Implement properly -->
<implementation name="IM_add_edf_genmdl" nodedef="ND_add_edf" sourcecode="{{in2}}" target="genmdl" /> <!-- TODO: Implement properly -->
<implementation name="IM_add_bsdf_genmdl" nodedef="ND_add_bsdf" sourcecode="mx::pbrlib::mx_add_bsdf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_add_edf_genmdl" nodedef="ND_add_edf" sourcecode="mx::pbrlib::mx_add_edf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_add_vdf_genmdl" nodedef="ND_add_vdf" sourcecode="mx::pbrlib::mx_add_vdf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />

<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genmdl" nodedef="ND_multiply_bsdfC" sourcecode="mx::pbrlib::mx_multiply_bsdf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_bsdfF_genmdl" nodedef="ND_multiply_bsdfF" sourcecode="mx::pbrlib::mx_multiply_bsdf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_edfC_genmdl" nodedef="ND_multiply_edfC" sourcecode="{{in1}}" target="genmdl" /> <!-- TODO: Implement properly -->
<implementation name="IM_multiply_edfF_genmdl" nodedef="ND_multiply_edfF" sourcecode="{{in1}}" target="genmdl" /> <!-- TODO: Implement properly -->
<implementation name="IM_multiply_edfC_genmdl" nodedef="ND_multiply_edfC" sourcecode="mx::pbrlib::mx_multiply_edf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_edfF_genmdl" nodedef="ND_multiply_edfF" sourcecode="mx::pbrlib::mx_multiply_edf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_vdfC_genmdl" nodedef="ND_multiply_vdfC" sourcecode="mx::pbrlib::mx_multiply_vdf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_vdfF_genmdl" nodedef="ND_multiply_vdfF" sourcecode="mx::pbrlib::mx_multiply_vdf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />

<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genmdl" nodedef="ND_roughness_anisotropy" sourcecode="mx::pbrlib::mx_roughness_anisotropy(mxp_roughness:{{roughness}}, mxp_anisotropy:{{anisotropy}})" target="genmdl" />
Expand Down
4 changes: 3 additions & 1 deletion libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,9 @@
<implementation name="IM_mix_vector3_vector3_genmdl" nodedef="ND_mix_vector3_vector3" sourcecode="math::lerp({{bg}}, {{fg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_vector4_genmdl" nodedef="ND_mix_vector4" sourcecode="math::lerp({{bg}}, {{fg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_vector4_vector4_genmdl" nodedef="ND_mix_vector4_vector4" sourcecode="math::lerp({{bg}}, {{fg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_surfaceshader_genmdl" nodedef="ND_mix_surfaceshader" sourcecode="mx::pbrlib::mx_mix_bsdf({{fg}}, {{bg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_surfaceshader_genmdl" nodedef="ND_mix_surfaceshader" sourcecode="mx::stdlib::mx_mix_surfaceshader({{fg}}, {{bg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_surfaceshader_genmdl" nodedef="ND_mix_volumeshader" sourcecode="mx::stdlib::mx_mix_volumeshader({{fg}}, {{bg}}, {{mix}})" target="genmdl" />
<implementation name="IM_mix_surfaceshader_genmdl" nodedef="ND_mix_displacementshader" sourcecode="mx::stdlib::mx_mix_displacementshader({{fg}}, {{bg}}, {{mix}})" target="genmdl" />

<!-- ======================================================================== -->
<!-- Conditional nodes -->
Expand Down
25 changes: 23 additions & 2 deletions source/MaterialXGenMdl/MdlSyntax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,35 @@ class MdlFilenameTypeSyntax : public ScalarTypeSyntax
{
return getDefaultValue(true);
}
// handle the empty texture, the fileprefix is passed
// assuming it ends with a slash ...
if (outputValue.back() == '/')
{
return getDefaultValue(true);
}
// ... or the last segment does not have an extension suffix
size_t idx_s = outputValue.find_last_of('/');
size_t idx_d = outputValue.find_last_of('.');
if (idx_d == std::string::npos || (idx_s != std::string::npos && idx_s > idx_d))
{
return getDefaultValue(true);
}

// prefix a slash in order to make MDL resource paths absolute i.e. to be found
// in the root of an MDL search path
// do not add the slash in case the path is explicitly relative
string pathSeparator("");
FilePath path(outputValue);
if (!path.isAbsolute())
size_t len = outputValue.size();
if (!path.isAbsolute() &&
!(len > 2 && outputValue[0] == '.' && outputValue[1] == '.' && outputValue[2] == '/') &&
!(len > 1 && outputValue[0] == '.' && outputValue[1] == '/'))
{
pathSeparator = "/";
}
return getName() + "(\"" + pathSeparator + outputValue + "\", tex::gamma_linear)";

// MDL is using leading slashes as separator
return getName() + "(\"" + pathSeparator + path.asString(FilePath::FormatPosix) + "\", tex::gamma_linear)";
}
};

Expand Down
6 changes: 3 additions & 3 deletions source/MaterialXGenMdl/mdl/materialx/core.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
// Document v1.37 REV2, January 19, 2020
// www.materialx.org
// in
// NVIDIA Material Definition Language 1.6
// NVIDIA Material Definition Language 1.7
// Language Specification
// Document version 1.6.1, December 16, 2019
// Document version 1.7.2, January 17, 2022
// www.nvidia.com/mdl

mdl 1.6;
mdl 1.7;

import ::math::*;
import ::tex::*;
Expand Down
113 changes: 59 additions & 54 deletions source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
// Document v1.37 REV2, July 16, 2019 (Revised October 17, 2019)
// see www.materialx.org
// in
// NVIDIA Material Definition Language 1.6
// NVIDIA Material Definition Language 1.7
// Language Specification
// Document version 1.6.1, December 16, 2019
// Document version 1.7.2, January 17, 2022
// www.nvidia.com/mdl

mdl 1.7;
Expand Down Expand Up @@ -313,33 +313,33 @@ export material mx_subsurface_bsdf(
)
);

// TODO: MDL's sheen BSDF has no possibility to configure the base BSDF, it is
// always a diffuse BSDF. Its color is configurable through the multiscatter
// tint and can be fed through the extra mxp_diffuse_tint input. A context
// analysis in the generator can map the color of the base to this input.
// To match with OSL, the sheen weight is scaled with average color as approximation of albedo.
// OSL uses the layer operator which mixes based on albedo.
export material mx_sheen_bsdf(
float mxp_weight = 1.0,
color mxp_color = color(1.0),
float mxp_roughness = 0.2,
float3 mxp_normal = state::normal(),
material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]],
color mxp_diffuse_color = color(1.0) // color of the base layer, MDL supports only diffuse
material mxp_base = material(
surface: material_surface(
scattering: df::diffuse_reflection_bsdf(
))) [[ anno::usage( "materialx:bsdf") ]]
) [[
anno::usage( "materialx:bsdf")
]]
= material(
surface: material_surface(
// using the mix seems to fit OSL best, at least in the test cases
scattering: df::weighted_layer(
weight: mxp_weight,
weight: math::average(mxp_color) * mxp_weight,
layer: df::sheen_bsdf(
roughness: mxp_roughness,
tint: mxp_color,
multiscatter_tint: mxp_diffuse_color
multiscatter_tint: color(1.0),
multiscatter: mxp_base.surface.scattering
),
base: mxp_base.surface.scattering,
normal: mxp_normal
)
),
normal: mxp_normal)),
// we need to carry volume properties along for SSS
ior: mxp_base.ior,
volume: mxp_base.volume
Expand Down Expand Up @@ -541,15 +541,20 @@ export material mx_thin_surface(
)
);

// TODO: emissive volumes not supported in MDL 1.6, EDF will be ignored here
// MDL 1.7, Volumes do support emssion, but not as EDF, just emission intensity.
// A uniform emission DF is the only practical DF here.
export material mx_volume(
material mxp_vdf = material() [[ anno::usage( "materialx:vdf") ]],
material mxp_edf = material() [[ anno::usage( "materialx:edf"), anno::unused() ]]
material mxp_edf = material() [[ anno::usage( "materialx:edf") ]]
) [[
anno::usage( "materialx:volumeshader")
]]
= material(
volume: mxp_vdf.volume
volume: material_volume(
absorption_coefficient: mxp_vdf.volume.absorption_coefficient,
scattering_coefficient: mxp_vdf.volume.scattering_coefficient,
emission_intensity: mxp_edf.surface.emission.intensity
)
);

export material mx_light(
Expand Down Expand Up @@ -631,26 +636,24 @@ export material mx_mix_bsdf(

export material mx_mix_edf(
material mxp_fg = material() [[ anno::usage( "materialx:edf") ]],
material mxp_bg = material() [[ anno::usage( "materialx:edf"), anno::unused() ]],
float mxp_mix = 0.0 [[ anno::unused() ]]
material mxp_bg = material() [[ anno::usage( "materialx:edf") ]],
float mxp_mix = 0.0
) [[
anno::usage( "materialx:edf")
]]
= mxp_fg;
// TODO: mixing two EDFs fails with the df::clamped_mix since the weights are uniform in MDL
// = material(
// surface: material_surface(
// emission: material_emission(
// emission: df::clamped_mix(
// df::edf_component[](
// df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
// df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
// ),
// intensity: mxp_mix * mxp_fg.surface.emission.intensity +
// (1.0 - mxp_mix) * mxp_bg.surface.emission.intensity
// )
// )
// );
= material(
surface: material_surface(
emission: material_emission(
emission: df::clamped_mix(
df::edf_component[](
df::edf_component( mxp_mix, mxp_fg.surface.emission.emission),
df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission))
),
intensity: mxp_mix * mxp_fg.surface.emission.intensity +
(1.0 - mxp_mix) * mxp_bg.surface.emission.intensity
)
)
);

export material mx_mix_vdf(
material mxp_fg = material() [[ anno::usage( "materialx:vdf") ]],
Expand Down Expand Up @@ -685,23 +688,24 @@ export material mx_add_bsdf(
]]
= material(
surface: material_surface(
scattering: df::weighted_layer(
weight: 0.5,
layer: mxp_in1.surface.scattering,
base: mxp_in2.surface.scattering
scattering: df::unbounded_mix(
df::bsdf_component[](
df::bsdf_component( 1.0, mxp_in1.surface.scattering),
df::bsdf_component( 1.0, mxp_in2.surface.scattering)
)
)
),
// we need to carry volume properties along for SSS
volume: material_volume(
scattering: df::clamped_mix(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( 0.5, mxp_in1.volume.scattering),
df::vdf_component( 0.5, mxp_in2.volume.scattering))
df::vdf_component( 1.0, mxp_in1.volume.scattering),
df::vdf_component( 1.0, mxp_in2.volume.scattering))
),
absorption_coefficient: 0.5 * mxp_in1.volume.absorption_coefficient +
0.5 * mxp_in2.volume.absorption_coefficient,
scattering_coefficient: 0.5 * mxp_in1.volume.scattering_coefficient +
0.5 * mxp_in2.volume.scattering_coefficient
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
mxp_in2.volume.absorption_coefficient,
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
mxp_in2.volume.scattering_coefficient
)
);

Expand All @@ -718,10 +722,10 @@ export material mx_add_edf(
= material(
surface: material_surface(
emission: material_emission(
emission: df::clamped_mix(
emission: df::unbounded_mix(
df::edf_component[](
df::edf_component( 0.5, mxp_in1.surface.emission.emission),
df::edf_component( 0.5, mxp_in2.surface.emission.emission))
df::edf_component( 1.0, mxp_in1.surface.emission.emission),
df::edf_component( 1.0, mxp_in2.surface.emission.emission))
),
intensity: mxp_in1.surface.emission.intensity + mxp_in2.surface.emission.intensity
)
Expand All @@ -738,17 +742,18 @@ export material mx_add_vdf(
anno::usage( "materialx:vdf")
]]
= material(
// assuming mixing the IOR is the best we can do here
ior: 0.5 * mxp_in1.ior + 0.5 * mxp_in2.ior,
volume: material_volume(
scattering: df::clamped_mix(
scattering: df::unbounded_mix(
df::vdf_component[](
df::vdf_component( 0.5, mxp_in1.volume.scattering),
df::vdf_component( 0.5, mxp_in2.volume.scattering))
df::vdf_component( 1.0, mxp_in1.volume.scattering),
df::vdf_component( 1.0, mxp_in2.volume.scattering))
),
absorption_coefficient: 0.5 * mxp_in1.volume.absorption_coefficient +
0.5 * mxp_in2.volume.absorption_coefficient,
scattering_coefficient: 0.5 * mxp_in1.volume.scattering_coefficient +
0.5 * mxp_in2.volume.scattering_coefficient
absorption_coefficient: mxp_in1.volume.absorption_coefficient +
mxp_in2.volume.absorption_coefficient,
scattering_coefficient: mxp_in1.volume.scattering_coefficient +
mxp_in2.volume.scattering_coefficient
)
);

Expand Down
Loading

0 comments on commit 4104569

Please sign in to comment.