Eevee: add blackbody shader node support.
This replaces the blackbody to RGB code with the simpler and faster one from Cycles. It's a little different but the other placing using this is the legacy volume drawing, so no need to stay compatible with that.
This commit is contained in:
parent
57609993d0
commit
77062e8bbb
Notes:
blender-bot
2023-02-14 06:17:14 +01:00
Referenced by issue #97876, Blackbody with 0 temperature is red, not black.
|
@ -656,135 +656,80 @@ void rgb_to_lab(float r, float g, float b, float *ll, float *la, float *lb)
|
|||
xyz_to_lab(x, y, z, ll, la, lb);
|
||||
}
|
||||
|
||||
static void xyz_to_lms(float x, float y, float z, float *l, float *m, float *s)
|
||||
{
|
||||
*l = 0.3897f * x + 0.6890f * y - 0.0787f * z;
|
||||
*m = -0.2298f * x + 1.1834f * y + 0.0464f * z;
|
||||
*s = z;
|
||||
}
|
||||
/* ****************************** blackbody ******************************** */
|
||||
|
||||
static void lms_to_xyz(float l, float m, float s, float *x, float *y, float *z)
|
||||
{
|
||||
*x = 1.9102f * l - 1.1121f * m + 0.2019f * s;
|
||||
*y = 0.3709f * l + 0.6290f * m + 0.0000f * s;
|
||||
*z = s;
|
||||
}
|
||||
|
||||
static void normalize_rgb(float rgb[3])
|
||||
{
|
||||
const float max = max_fff(rgb[0], rgb[1], rgb[2]);
|
||||
|
||||
if (max > 0.0f) {
|
||||
mul_v3_fl(rgb, 1.0f / max);
|
||||
}
|
||||
}
|
||||
|
||||
/* Color rendering of spectra, adapted from public domain code by John Walker,
|
||||
* http://www.fourmilab.ch/
|
||||
/* Calculate color in range 800..12000 using an approximation
|
||||
* a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
|
||||
* Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
|
||||
* which is enough to get the same 8 bit/channel color.
|
||||
*/
|
||||
|
||||
static void spectrum_to_xyz(float temperature, float xyz[3])
|
||||
static const float blackbody_table_r[6][3] = {
|
||||
{ 2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f },
|
||||
{ 3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f },
|
||||
{ 4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f },
|
||||
{ 4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f },
|
||||
{ 4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f },
|
||||
{ 3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f },
|
||||
};
|
||||
|
||||
static const float blackbody_table_g[6][3] = {
|
||||
{ -7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f },
|
||||
{ -1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f },
|
||||
{ -1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f },
|
||||
{ -1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f },
|
||||
{ -1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f },
|
||||
{ -5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f },
|
||||
};
|
||||
|
||||
static const float blackbody_table_b[6][4] = {
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
{ -2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f },
|
||||
{ -2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f },
|
||||
{ 6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f },
|
||||
};
|
||||
|
||||
static void blackbody_temperature_to_rgb(float rgb[3], float t)
|
||||
{
|
||||
int i;
|
||||
float lambda, x = 0.0f, y = 0.0f, z = 0.0f, xyz_sum;
|
||||
|
||||
/* CIE colour matching functions xBar, yBar, and zBar for wavelengths from
|
||||
* 380 through 780 nanometers, every 5 nanometers.
|
||||
* For a wavelength lambda in this range:
|
||||
*
|
||||
* cie_colour_match[(lambda - 380) / 5][0] = xBar
|
||||
* cie_colour_match[(lambda - 380) / 5][1] = yBar
|
||||
* cie_colour_match[(lambda - 380) / 5][2] = zBar
|
||||
*/
|
||||
|
||||
const float cie_colour_match[81][3] = {
|
||||
{0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
|
||||
{0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
|
||||
{0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
|
||||
{0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
|
||||
{0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
|
||||
{0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
|
||||
{0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
|
||||
{0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
|
||||
{0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
|
||||
{0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
|
||||
{0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
|
||||
{0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
|
||||
{0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
|
||||
{0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
|
||||
{1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
|
||||
{1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
|
||||
{0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
|
||||
{0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
|
||||
{0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
|
||||
{0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
|
||||
{0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
|
||||
{0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
|
||||
{0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
|
||||
{0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
|
||||
{0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
|
||||
{0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
|
||||
{0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}
|
||||
};
|
||||
|
||||
for (i = 0, lambda = 380.0f; lambda < 780.1f; i++, lambda += 5.0f) {
|
||||
/* wavelength in meter */
|
||||
const float wlm = lambda * 1e-9f;
|
||||
const float Me = (3.74183e-16f * powf(wlm, -5.0f)) / (expf(1.4388e-2f / (wlm * temperature)) - 1.0f);
|
||||
|
||||
x += Me * cie_colour_match[i][0];
|
||||
y += Me * cie_colour_match[i][1];
|
||||
z += Me * cie_colour_match[i][2];
|
||||
if(t >= 12000.0f) {
|
||||
rgb[0] = 0.826270103f;
|
||||
rgb[1] = 0.994478524f;
|
||||
rgb[2] = 1.56626022f;
|
||||
}
|
||||
else if(t < 965.0f) {
|
||||
rgb[0] = 4.70366907f;
|
||||
rgb[1] = 0.0f;
|
||||
rgb[2] = 0.0f;
|
||||
}
|
||||
else {
|
||||
int i = (t >= 6365.0f)? 5:
|
||||
(t >= 3315.0f)? 4:
|
||||
(t >= 1902.0f)? 3:
|
||||
(t >= 1449.0f)? 2:
|
||||
(t >= 1167.0f)? 1: 0;
|
||||
|
||||
xyz_sum = (x + y + z);
|
||||
const float *r = blackbody_table_r[i];
|
||||
const float *g = blackbody_table_g[i];
|
||||
const float *b = blackbody_table_b[i];
|
||||
|
||||
xyz[0] = x / xyz_sum;
|
||||
xyz[1] = y / xyz_sum;
|
||||
xyz[2] = z / xyz_sum;
|
||||
const float t_inv = 1.0f / t;
|
||||
rgb[0] = r[0] * t_inv + r[1] * t + r[2];
|
||||
rgb[1] = g[0] * t_inv + g[1] * t + g[2];
|
||||
rgb[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
|
||||
}
|
||||
}
|
||||
|
||||
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
|
||||
{
|
||||
int i, j = 0, dj = 1;
|
||||
float rgb[3], xyz[3], lms[3], lms_w[3];
|
||||
float bb_temp;
|
||||
for (int i = 0; i < width; i++) {
|
||||
float temperature = min + (max - min) / (float)width * (float)i;
|
||||
|
||||
if (min < max) {
|
||||
SWAP(float, min, max);
|
||||
j = width - 1;
|
||||
dj = -1;
|
||||
}
|
||||
float rgb[3];
|
||||
blackbody_temperature_to_rgb(rgb, temperature);
|
||||
|
||||
for (i = 0; i < width; i++, j += dj) {
|
||||
bb_temp = min + (max - min) / (float)width * (float)i;
|
||||
|
||||
/* integrate blackbody radiation spectrum to XYZ */
|
||||
spectrum_to_xyz(bb_temp, xyz);
|
||||
|
||||
/* normalize highest temperature to white (in LMS system) */
|
||||
xyz_to_lms(xyz[0], xyz[1], xyz[2], &lms[0], &lms[1], &lms[2]);
|
||||
|
||||
if (i == 0) {
|
||||
lms_w[0] = 1.0f / lms[0];
|
||||
lms_w[1] = 1.0f / lms[1];
|
||||
lms_w[2] = 1.0f / lms[2];
|
||||
}
|
||||
|
||||
mul_v3_v3(lms, lms_w);
|
||||
|
||||
lms_to_xyz(lms[0], lms[1], lms[2], &xyz[0], &xyz[1], &xyz[2]);
|
||||
|
||||
/* convert to RGB */
|
||||
xyz_to_rgb(xyz[0], xyz[1], xyz[2], &rgb[0], &rgb[1], &rgb[2], BLI_XYZ_CIE);
|
||||
constrain_rgb(&rgb[0], &rgb[1], &rgb[2]);
|
||||
normalize_rgb(rgb);
|
||||
|
||||
copy_v3_v3(&r_table[(j << 2)], rgb);
|
||||
|
||||
if (rgb[2] > 0.1f)
|
||||
r_table[(j << 2) + 3] = rgb[2];
|
||||
else
|
||||
r_table[(j << 2) + 3] = 0.0f;
|
||||
copy_v3_v3(&r_table[i * 4], rgb);
|
||||
r_table[i * 4 + 3] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3075,6 +3075,20 @@ void node_volume_absorption(vec4 color, float density, out Closure result)
|
|||
#endif
|
||||
}
|
||||
|
||||
void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color)
|
||||
{
|
||||
if(temperature >= 12000.0) {
|
||||
color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
|
||||
}
|
||||
else if(temperature < 965.0) {
|
||||
color = vec4(4.70366907, 0.0, 0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
float t = (temperature - 965.0) / (12000.0 - 965.0);
|
||||
color = vec4(texture(spectrummap, vec2(t, 0.0)).rgb, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* closures */
|
||||
|
||||
void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
|
||||
|
|
|
@ -38,6 +38,16 @@ static bNodeSocketTemplate sh_node_blackbody_out[] = {
|
|||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
static int node_shader_gpu_blackbody(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
|
||||
{
|
||||
const int size = 256;
|
||||
float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
|
||||
|
||||
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
|
||||
|
||||
return GPU_stack_link(mat, node, "node_blackbody", in, out, GPU_texture(size, data));
|
||||
}
|
||||
|
||||
/* node type definition */
|
||||
void register_node_type_sh_blackbody(void)
|
||||
{
|
||||
|
@ -49,6 +59,7 @@ void register_node_type_sh_blackbody(void)
|
|||
node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
|
||||
node_type_init(&ntype, NULL);
|
||||
node_type_storage(&ntype, "", NULL, NULL);
|
||||
node_type_gpu(&ntype, node_shader_gpu_blackbody);
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue