Skip to content

Commit 3e838e2

Browse files
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.
1 parent 2c0c7ea commit 3e838e2

13 files changed

Lines changed: 129 additions & 6 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/// XYZ to Rec.709 RGB colorspace conversion
2+
const mat3 XYZ_to_RGB = mat3( 3.2406, -0.9689, 0.0557,
3+
-1.5372, 1.8758, -0.2040,
4+
-0.4986, 0.0415, 1.0570);
5+
6+
void mx_blackbody(float temperatureKelvin, out vec3 colorValue)
7+
{
8+
float xc, yc;
9+
float t, t2, t3, xc2, xc3;
10+
11+
// if value outside valid range of approximation clamp to accepted temperature range
12+
temperatureKelvin = clamp(temperatureKelvin, 1667.0, 25000.0);
13+
14+
t = 1000.0 / temperatureKelvin;
15+
t2 = t * t;
16+
t3 = t * t * t;
17+
18+
// Cubic spline approximation for Kelvin temperature to sRGB conversion
19+
// (https://en.wikipedia.org/wiki/Planckian_locus#Approximation)
20+
if (temperatureKelvin < 4000.0) { // 1667K <= temperatureKelvin < 4000K
21+
xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910;
22+
}
23+
else { // 4000K <= temperatureKelvin <= 25000K
24+
xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390;
25+
}
26+
xc2 = xc * xc;
27+
xc3 = xc * xc * xc;
28+
29+
if (temperatureKelvin < 2222.0) { // 1667K <= temperatureKelvin < 2222K
30+
yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683;
31+
}
32+
else if (temperatureKelvin < 4000.0) { // 2222K <= temperatureKelvin < 4000K
33+
yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867;
34+
}
35+
else { // 4000K <= temperatureKelvin <= 25000K
36+
yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483;
37+
}
38+
39+
if (yc <= 0.0) { // avoid division by zero
40+
colorValue = vec3(1.0);
41+
return;
42+
}
43+
44+
vec3 XYZ = vec3(xc / yc, 1.0, (1.0 - xc - yc) / yc);
45+
46+
colorValue = XYZ_to_RGB * XYZ;
47+
colorValue = max(colorValue, vec3(0.0));
48+
}

libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,7 @@
7474
<!-- <artistic_ior> -->
7575
<implementation name="IM_artistic_ior_genglsl" nodedef="ND_artistic_ior" file="mx_artistic_ior.glsl" function="mx_artistic_ior" target="genglsl" />
7676

77+
<!-- <blackbody> -->
78+
<implementation name="IM_blackbody_genglsl" nodedef="ND_blackbody" file="mx_blackbody.glsl" function="mx_blackbody" target="genglsl" />
79+
7780
</materialx>

libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,7 @@
7171
<!-- <artistic_ior> -->
7272
<implementation name="IM_artistic_ior_genmsl" nodedef="ND_artistic_ior" file="../genglsl/mx_artistic_ior.glsl" function="mx_artistic_ior" target="genmsl" />
7373

74+
<!-- <blackbody> -->
75+
<implementation name="IM_blackbody_genmsl" nodedef="ND_blackbody" file="../genglsl/mx_blackbody.glsl" function="mx_blackbody" target="genmsl" />
76+
7477
</materialx>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
void mx_blackbody(float temperature, output color color_value)
2+
{
3+
float xc, yc;
4+
float t, t2, t3, xc2, xc3;
5+
6+
// if value outside valid range of approximation clamp to accepted temperature range
7+
temperature = clamp(temperature, 1667.0, 25000.0);
8+
9+
t = 1000.0 / temperature;
10+
t2 = t * t;
11+
t3 = t * t * t;
12+
13+
// Cubic spline approximation for Kelvin temperature to sRGB conversion
14+
// (https://en.wikipedia.org/wiki/Planckian_locus#Approximation)
15+
if (temperature < 4000.0) { // 1667K <= temperature < 4000K
16+
xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910;
17+
}
18+
else { // 4000K <= temperature <= 25000K
19+
xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390;
20+
}
21+
xc2 = xc * xc;
22+
xc3 = xc * xc * xc;
23+
24+
if (temperature < 2222.0) { // 1667K <= temperature < 2222K
25+
yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683;
26+
}
27+
else if (temperature < 4000.0) { // 2222K <= temperature < 4000K
28+
yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867;
29+
}
30+
else { // 4000K <= temperature <= 25000K
31+
yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483;
32+
}
33+
34+
if (yc <= 0.0) { // avoid division by zero
35+
color_value = color(1.0);
36+
return;
37+
}
38+
39+
vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc);
40+
41+
/// XYZ to Rec.709 RGB colorspace conversion
42+
matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557,
43+
-1.5372, 1.8758, -0.2040,
44+
-0.4986, 0.0415, 1.0570);
45+
46+
color_value = transform(XYZ_to_RGB, XYZ);
47+
color_value = max(color_value, vector(0.0));
48+
}

libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,7 @@
7171
<!-- <artistic_ior> -->
7272
<implementation name="IM_artistic_ior_genosl" nodedef="ND_artistic_ior" file="mx_artistic_ior.osl" function="mx_artistic_ior" target="genosl" />
7373

74+
<!-- <blackbody> -->
75+
<implementation name="IM_blackbody_genosl" nodedef="ND_blackbody" file="mx_blackbody.osl" function="mx_blackbody" target="genosl" />
76+
7477
</materialx>

libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,7 @@
7171
<!-- <artistic_ior> -->
7272
<implementation name="IM_artistic_ior_genosl" nodedef="ND_artistic_ior" file="mx_artistic_ior.osl" function="mx_artistic_ior" target="genosl" />
7373

74+
<!-- <blackbody> -->
75+
<implementation name="IM_blackbody_genosl" nodedef="ND_blackbody" file="mx_blackbody.osl" function="mx_blackbody" target="genosl" />
76+
7477
</materialx>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0"?>
2+
<materialx version="1.38" colorspace="lin_rec709">
3+
<nodegraph name="NG_blackbody">
4+
<input name="blackbody_temperature" type="float" value="5000.0" uimin="1500.0" uimax="25000.0" uistep="100.0" uiname="Blackbody Temperature Kelvin" />
5+
<blackbody name="blackbody_color_out" type="color3">
6+
<input name="temperature" type="float" interfacename="blackbody_temperature" />
7+
</blackbody>
8+
<output name="emission_color_output" type="color3" nodename="blackbody_color_out" />
9+
</nodegraph>
10+
<surface_unlit name="SR_blackbody" type="surfaceshader">
11+
<input name="emission_color" type="color3" nodegraph="NG_blackbody" output="emission_color_output" />
12+
</surface_unlit>
13+
<surfacematerial name="Blackbody" type="material">
14+
<input name="surfaceshader" type="surfaceshader" nodename="SR_blackbody" />
15+
</surfacematerial>
16+
</materialx>

source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ TEST_CASE("GenShader: GLSL Implementation Check", "[genglsl]")
8585

8686
mx::StringSet generatorSkipNodeTypes;
8787
mx::StringSet generatorSkipNodeDefs;
88-
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48);
88+
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 47);
8989
}
9090

9191
TEST_CASE("GenShader: GLSL Unique Names", "[genglsl]")

source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]")
9393
generatorSkipNodeTypes.insert("light");
9494
mx::StringSet generatorSkipNodeDefs;
9595

96-
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 49);
96+
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48);
9797
}
9898

9999

source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]")
8484

8585
mx::StringSet generatorSkipNodeTypes;
8686
mx::StringSet generatorSkipNodeDefs;
87-
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 48);
87+
GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 47);
8888
}
8989

9090
TEST_CASE("GenShader: MSL Unique Names", "[genmsl]")

0 commit comments

Comments
 (0)