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