From 3e838e2f4b4bcc434bd0e99f0e382c8d475b322a Mon Sep 17 00:00:00 2001 From: nicolassavva-autodesk <61437351+nicolassavva-autodesk@users.noreply.github.com> Date: Wed, 12 Jul 2023 10:26:22 -0700 Subject: [PATCH] Add blackbody PBR node implementations (#1367) Address the missing targets for the PBR blackbody node implementation using the following approximation: Wikipedia: Planckian Locus Approximation Add a simple unlit surface material example using the above blackbody node for emission. Reenable blackbody node tests. --- libraries/pbrlib/genglsl/mx_blackbody.glsl | 48 +++++++++++++++++++ .../pbrlib/genglsl/pbrlib_genglsl_impl.mtlx | 3 ++ .../pbrlib/genmsl/pbrlib_genmsl_impl.mtlx | 3 ++ libraries/pbrlib/genosl/mx_blackbody.osl | 48 +++++++++++++++++++ .../pbrlib/genosl/pbrlib_genosl_impl.legacy | 3 ++ .../pbrlib/genosl/pbrlib_genosl_impl.mtlx | 3 ++ .../TestSuite/pbrlib/bsdf/blackbody.mtlx | 16 +++++++ .../MaterialXGenGlsl/GenGlsl.cpp | 2 +- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 2 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 1 - source/MaterialXView/Editor.cpp | 2 +- 13 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 libraries/pbrlib/genglsl/mx_blackbody.glsl create mode 100644 libraries/pbrlib/genosl/mx_blackbody.osl create mode 100644 resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx diff --git a/libraries/pbrlib/genglsl/mx_blackbody.glsl b/libraries/pbrlib/genglsl/mx_blackbody.glsl new file mode 100644 index 0000000000..55d5c87541 --- /dev/null +++ b/libraries/pbrlib/genglsl/mx_blackbody.glsl @@ -0,0 +1,48 @@ +/// XYZ to Rec.709 RGB colorspace conversion +const mat3 XYZ_to_RGB = mat3( 3.2406, -0.9689, 0.0557, + -1.5372, 1.8758, -0.2040, + -0.4986, 0.0415, 1.0570); + +void mx_blackbody(float temperatureKelvin, out vec3 colorValue) +{ + float xc, yc; + float t, t2, t3, xc2, xc3; + + // if value outside valid range of approximation clamp to accepted temperature range + temperatureKelvin = clamp(temperatureKelvin, 1667.0, 25000.0); + + t = 1000.0 / temperatureKelvin; + t2 = t * t; + t3 = t * t * t; + + // Cubic spline approximation for Kelvin temperature to sRGB conversion + // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) + if (temperatureKelvin < 4000.0) { // 1667K <= temperatureKelvin < 4000K + xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; + } + else { // 4000K <= temperatureKelvin <= 25000K + xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; + } + xc2 = xc * xc; + xc3 = xc * xc * xc; + + if (temperatureKelvin < 2222.0) { // 1667K <= temperatureKelvin < 2222K + yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; + } + else if (temperatureKelvin < 4000.0) { // 2222K <= temperatureKelvin < 4000K + yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; + } + else { // 4000K <= temperatureKelvin <= 25000K + yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; + } + + if (yc <= 0.0) { // avoid division by zero + colorValue = vec3(1.0); + return; + } + + vec3 XYZ = vec3(xc / yc, 1.0, (1.0 - xc - yc) / yc); + + colorValue = XYZ_to_RGB * XYZ; + colorValue = max(colorValue, vec3(0.0)); +} diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx index b94f513d82..fa4617375f 100644 --- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -74,4 +74,7 @@ + + + diff --git a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx index 1900f1e824..8d1d2a4729 100644 --- a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx +++ b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx @@ -71,4 +71,7 @@ + + + diff --git a/libraries/pbrlib/genosl/mx_blackbody.osl b/libraries/pbrlib/genosl/mx_blackbody.osl new file mode 100644 index 0000000000..8b4de5ba9f --- /dev/null +++ b/libraries/pbrlib/genosl/mx_blackbody.osl @@ -0,0 +1,48 @@ +void mx_blackbody(float temperature, output color color_value) +{ + float xc, yc; + float t, t2, t3, xc2, xc3; + + // if value outside valid range of approximation clamp to accepted temperature range + temperature = clamp(temperature, 1667.0, 25000.0); + + t = 1000.0 / temperature; + t2 = t * t; + t3 = t * t * t; + + // Cubic spline approximation for Kelvin temperature to sRGB conversion + // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) + if (temperature < 4000.0) { // 1667K <= temperature < 4000K + xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; + } + else { // 4000K <= temperature <= 25000K + xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; + } + xc2 = xc * xc; + xc3 = xc * xc * xc; + + if (temperature < 2222.0) { // 1667K <= temperature < 2222K + yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; + } + else if (temperature < 4000.0) { // 2222K <= temperature < 4000K + yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; + } + else { // 4000K <= temperature <= 25000K + yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; + } + + if (yc <= 0.0) { // avoid division by zero + color_value = color(1.0); + return; + } + + vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc); + + /// XYZ to Rec.709 RGB colorspace conversion + matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, + -1.5372, 1.8758, -0.2040, + -0.4986, 0.0415, 1.0570); + + color_value = transform(XYZ_to_RGB, XYZ); + color_value = max(color_value, vector(0.0)); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy index d7ccf80906..6ab7cc9e61 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy @@ -71,4 +71,7 @@ + + + diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index b37dc79fcd..7a38f0fb12 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -71,4 +71,7 @@ + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx new file mode 100644 index 0000000000..f2d9b193f3 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp index 54b6fbf420..339d3853cb 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp @@ -85,7 +85,7 @@ TEST_CASE("GenShader: GLSL Implementation Check", "[genglsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 47); } TEST_CASE("GenShader: GLSL Unique Names", "[genglsl]") diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index e565071caa..1a3e127cde 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -93,7 +93,7 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 49); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48); } diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index e3bcc7cfa1..03dbcbde69 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,7 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 47); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index 9d3fa78db4..13a8b5ffdf 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -89,7 +89,7 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 49); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 75b69ff93b..863cd1af05 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -94,7 +94,6 @@ void checkImplementations(mx::GenContext& context, "arrayappend", "displacement", "volume", - "blackbody", "curveadjust", "conical_edf", "measured_edf", diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index a4c6d3f675..ff91f0f129 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -701,7 +701,7 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la if (ui) { - std::pair range(0.0f, 0.0f); + std::pair range(0.0f, 1.0f); if (ui->uiMin) { box->set_min_value(ui->uiMin->asA());