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());