@woosh/meep-engine 2.131.16 → 2.131.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/color/illuminant/planckian_radiance.d.ts.map +1 -1
- package/src/core/color/illuminant/planckian_radiance.js +8 -0
- package/src/core/color/kelvin/kelvin_to_rgb.d.ts +4 -1
- package/src/core/color/kelvin/kelvin_to_rgb.d.ts.map +1 -1
- package/src/core/color/kelvin/kelvin_to_rgb.js +126 -27
- package/src/core/color/kelvin/rgb_to_kelvin.d.ts +4 -1
- package/src/core/color/kelvin/rgb_to_kelvin.d.ts.map +1 -1
- package/src/core/color/kelvin/rgb_to_kelvin.js +34 -9
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"description": "Pure JavaScript game engine. Fully featured and production ready.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Alexander Goldring",
|
|
8
|
-
"version": "2.131.
|
|
8
|
+
"version": "2.131.17",
|
|
9
9
|
"main": "build/meep.module.js",
|
|
10
10
|
"module": "build/meep.module.js",
|
|
11
11
|
"exports": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planckian_radiance.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/illuminant/planckian_radiance.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"planckian_radiance.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/illuminant/planckian_radiance.js"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,6CAJW,MAAM,KACN,MAAM,GACJ,MAAM,CAyBlB"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Second radiation constant (m·K)
|
|
3
5
|
*
|
|
@@ -14,6 +16,12 @@ const PLANCK_C2 = 1.438776877e-2;
|
|
|
14
16
|
* @returns {number} Relative spectral power
|
|
15
17
|
*/
|
|
16
18
|
export function planckian_radiance(lambda_m, T) {
|
|
19
|
+
assert.isNumber(lambda_m, 'lambda_m');
|
|
20
|
+
assert.notNaN(lambda_m, 'lambda_m');
|
|
21
|
+
|
|
22
|
+
assert.isNumber(T, 'T');
|
|
23
|
+
assert.notNaN(T, 'T');
|
|
24
|
+
|
|
17
25
|
const lambda_T = lambda_m * T;
|
|
18
26
|
const exponent = PLANCK_C2 / lambda_T;
|
|
19
27
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
+
*
|
|
3
|
+
* Converts Kelvin temperature to RGB.
|
|
4
|
+
* Handles ranges 0K - 40000K
|
|
2
5
|
*
|
|
3
6
|
* Note: if you will need to covert the output to linear space ({@link sRGB_to_linear}) if you intend to perform any mixing on the color.
|
|
4
7
|
*
|
|
5
|
-
* @param {number[]} result RGB output
|
|
8
|
+
* @param {number[]} result result RGB output (sRGB Gamma Corrected)
|
|
6
9
|
* @param {number} result_offset
|
|
7
10
|
* @param {number} temperature in Kelvin
|
|
8
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kelvin_to_rgb.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/kelvin/kelvin_to_rgb.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kelvin_to_rgb.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/kelvin/kelvin_to_rgb.js"],"names":[],"mappings":"AA6FA;;;;;;;;;;;;;;GAcG;AACH,sCARW,MAAM,EAAE,iBACR,MAAM,eACN,MAAM,QA6DhB"}
|
|
@@ -1,11 +1,104 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
2
|
import { clamp01 } from "../../math/clamp01.js";
|
|
3
|
+
import { inverseLerp } from "../../math/inverseLerp.js";
|
|
4
|
+
import { lerp } from "../../math/lerp.js";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Red-dominant approximation
|
|
9
|
+
*
|
|
10
|
+
* Valid for < 6600K
|
|
11
|
+
*
|
|
12
|
+
* @param {number[]} out
|
|
13
|
+
* @param {number} t K/100
|
|
14
|
+
*/
|
|
15
|
+
function approximate_regime_red(out, t) {
|
|
16
|
+
|
|
17
|
+
const r = 1;
|
|
18
|
+
|
|
19
|
+
const g = clamp01(
|
|
20
|
+
-0.6088425710866344 - 0.001748900018414868 * (t - 2) + 0.4097731842899564 * Math.log(t - 2)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const b = t <= 20 ? 0 : clamp01(
|
|
24
|
+
-0.9990954974165059 + 0.0032447435545127036 * (t - 10) + 0.453646839257496 * Math.log(t - 10)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
out[0] = r;
|
|
28
|
+
out[1] = g;
|
|
29
|
+
out[2] = b;
|
|
30
|
+
}
|
|
31
|
+
|
|
3
32
|
|
|
4
33
|
/**
|
|
34
|
+
* Blue-dominant approximation
|
|
35
|
+
*
|
|
36
|
+
* Valid for > 6600K
|
|
37
|
+
*
|
|
38
|
+
* @param {number[]} out
|
|
39
|
+
* @param {number} t K/100
|
|
40
|
+
*/
|
|
41
|
+
function approximate_regime_blue(out, t) {
|
|
42
|
+
|
|
43
|
+
const r = clamp01(
|
|
44
|
+
1.3803015908551253 + 0.0004478684462124118 * (t - 55) - 0.15785750232675008 * Math.log(t - 55)
|
|
45
|
+
); // in normalized scale
|
|
46
|
+
|
|
47
|
+
const g = clamp01(
|
|
48
|
+
1.2762722061615583 + 0.0003115080994769546 * (t - 50) - 0.11013841706194392 * Math.log(t - 50)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const b = 1;
|
|
52
|
+
|
|
53
|
+
out[0] = r;
|
|
54
|
+
out[1] = g;
|
|
55
|
+
out[2] = b;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Black body
|
|
60
|
+
*
|
|
61
|
+
* Valid for < 1000K
|
|
62
|
+
*
|
|
63
|
+
* @param {number[]} out
|
|
64
|
+
* @param {number} t K/100
|
|
65
|
+
*/
|
|
66
|
+
function approximate_regime_blackbody(out, t) {
|
|
67
|
+
// 1. Handle "Black Body" cooling (below 1000K)
|
|
68
|
+
|
|
69
|
+
// These are the values the algorithm produces at exactly 1000K (t=10).
|
|
70
|
+
// We lock the hue here and just fade the brightness to zero.
|
|
71
|
+
const k1000_r = 1;
|
|
72
|
+
const k1000_g = 0.22926561084500907;
|
|
73
|
+
const k1000_b = 0;
|
|
74
|
+
|
|
75
|
+
// The Draper point (approx 798K) is where objects begin to glow visible red.
|
|
76
|
+
const DRAPER_POINT = 7.98; // 798K
|
|
77
|
+
|
|
78
|
+
// Note: We are attenuating Gamma-corrected values here.
|
|
79
|
+
// Physically strictly incorrect (should be linear), but visually acceptable
|
|
80
|
+
// and faster for this specific "fade to black" effect.
|
|
81
|
+
const brightness = Math.max(0, inverseLerp(DRAPER_POINT, 10, t));
|
|
82
|
+
|
|
83
|
+
out[0] = k1000_r * brightness;
|
|
84
|
+
out[1] = k1000_g * brightness;
|
|
85
|
+
out[2] = k1000_b * brightness;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Avoid heap allocation in the main function
|
|
90
|
+
* @type {number[]}
|
|
91
|
+
*/
|
|
92
|
+
const scratch_rgb = [0, 0, 0];
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
*
|
|
96
|
+
* Converts Kelvin temperature to RGB.
|
|
97
|
+
* Handles ranges 0K - 40000K
|
|
5
98
|
*
|
|
6
99
|
* Note: if you will need to covert the output to linear space ({@link sRGB_to_linear}) if you intend to perform any mixing on the color.
|
|
7
100
|
*
|
|
8
|
-
* @param {number[]} result RGB output
|
|
101
|
+
* @param {number[]} result result RGB output (sRGB Gamma Corrected)
|
|
9
102
|
* @param {number} result_offset
|
|
10
103
|
* @param {number} temperature in Kelvin
|
|
11
104
|
*
|
|
@@ -22,44 +115,50 @@ export function kelvin_to_rgb(
|
|
|
22
115
|
assert.isNonNegativeInteger(result_offset, "result_offset");
|
|
23
116
|
assert.isNumber(temperature, "temperature");
|
|
24
117
|
|
|
25
|
-
let r;
|
|
26
|
-
let g;
|
|
27
|
-
let b;
|
|
28
|
-
|
|
29
118
|
// Temperature divided by 100 for calculations
|
|
30
119
|
const t = temperature / 100;
|
|
31
120
|
|
|
32
|
-
if (t
|
|
121
|
+
if (t < 10) {
|
|
122
|
+
|
|
123
|
+
approximate_regime_blackbody(scratch_rgb, t);
|
|
124
|
+
|
|
125
|
+
} else {
|
|
126
|
+
|
|
127
|
+
const BLEND_MIN = 65;
|
|
128
|
+
const BLEND_MAX = 67;
|
|
129
|
+
|
|
130
|
+
if (t < BLEND_MIN) {
|
|
33
131
|
|
|
34
|
-
|
|
132
|
+
approximate_regime_red(scratch_rgb, t);
|
|
35
133
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
134
|
+
} else if (t > BLEND_MAX) {
|
|
135
|
+
|
|
136
|
+
approximate_regime_blue(scratch_rgb, t);
|
|
39
137
|
|
|
40
|
-
if (t <= 20) {
|
|
41
|
-
b = 0;
|
|
42
138
|
} else {
|
|
43
139
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
140
|
+
// blend the two regimes to avoid discontinuity
|
|
141
|
+
const alpha = inverseLerp(BLEND_MIN, BLEND_MAX, t);
|
|
47
142
|
|
|
48
|
-
|
|
49
|
-
|
|
143
|
+
approximate_regime_red(scratch_rgb, t);
|
|
144
|
+
const r0 = scratch_rgb[0];
|
|
145
|
+
const g0 = scratch_rgb[1];
|
|
146
|
+
const b0 = scratch_rgb[2];
|
|
50
147
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
148
|
+
approximate_regime_blue(scratch_rgb, t);
|
|
149
|
+
const r1 = scratch_rgb[0];
|
|
150
|
+
const g1 = scratch_rgb[1];
|
|
151
|
+
const b1 = scratch_rgb[2];
|
|
54
152
|
|
|
55
|
-
|
|
56
|
-
1
|
|
57
|
-
|
|
153
|
+
scratch_rgb[0] = lerp(r0, r1, alpha);
|
|
154
|
+
scratch_rgb[1] = lerp(g0, g1, alpha);
|
|
155
|
+
scratch_rgb[2] = lerp(b0, b1, alpha);
|
|
156
|
+
|
|
157
|
+
}
|
|
58
158
|
|
|
59
|
-
b = 1;
|
|
60
159
|
}
|
|
61
160
|
|
|
62
|
-
result[result_offset + 0] =
|
|
63
|
-
result[result_offset + 1] =
|
|
64
|
-
result[result_offset + 2] =
|
|
161
|
+
result[result_offset + 0] = scratch_rgb[0];
|
|
162
|
+
result[result_offset + 1] = scratch_rgb[1];
|
|
163
|
+
result[result_offset + 2] = scratch_rgb[2];
|
|
65
164
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Estimates the Color Temperature (Kelvin) from an RGB input.
|
|
2
3
|
*
|
|
3
|
-
* @see https://www.zombieprototypes.com/?p=210
|
|
4
4
|
* @param {number[]|ArrayLike<number>|{0:number,1:number,2:number}} input input array
|
|
5
5
|
* @param {number} [input_offset=0] offset into input array
|
|
6
|
+
* @returns {number} Temperature in Kelvin (approx 1000 to 40000)
|
|
7
|
+
*
|
|
8
|
+
* @see https://www.zombieprototypes.com/?p=210
|
|
6
9
|
*/
|
|
7
10
|
export function rgb_to_kelvin(input: number[] | ArrayLike<number> | {
|
|
8
11
|
0: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rgb_to_kelvin.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/kelvin/rgb_to_kelvin.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rgb_to_kelvin.d.ts","sourceRoot":"","sources":["../../../../../src/core/color/kelvin/rgb_to_kelvin.js"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,qCANW,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GAAC;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,iBACvD,MAAM,GACJ,MAAM,CA4DlB"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
2
|
import { kelvin_to_rgb } from "./kelvin_to_rgb.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Save allocation with re-usable scratch
|
|
6
|
+
* @type {number[]}
|
|
7
|
+
*/
|
|
4
8
|
const scratch_rgb = [];
|
|
5
9
|
|
|
6
10
|
/**
|
|
11
|
+
* Estimates the Color Temperature (Kelvin) from an RGB input.
|
|
7
12
|
*
|
|
8
|
-
* @see https://www.zombieprototypes.com/?p=210
|
|
9
13
|
* @param {number[]|ArrayLike<number>|{0:number,1:number,2:number}} input input array
|
|
10
14
|
* @param {number} [input_offset=0] offset into input array
|
|
15
|
+
* @returns {number} Temperature in Kelvin (approx 1000 to 40000)
|
|
16
|
+
*
|
|
17
|
+
* @see https://www.zombieprototypes.com/?p=210
|
|
11
18
|
*/
|
|
12
19
|
export function rgb_to_kelvin(
|
|
13
20
|
input,
|
|
@@ -17,32 +24,50 @@ export function rgb_to_kelvin(
|
|
|
17
24
|
assert.isNonNegativeInteger(input_offset, "input_offset");
|
|
18
25
|
|
|
19
26
|
const r = input[input_offset];
|
|
20
|
-
const g = input[input_offset + 1];
|
|
21
27
|
const b = input[input_offset + 2];
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
let minTemperature = 1000;
|
|
30
|
+
let maxTemperature = 40000;
|
|
31
|
+
|
|
32
|
+
if (r + b === 0) {
|
|
33
|
+
// black, effectively 0 Kelvin
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (r === 0) {
|
|
38
|
+
// blue dominance, produce maximum
|
|
39
|
+
// also, avoid division by 0
|
|
40
|
+
return maxTemperature;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const expected_blue_red_ratio = b / r;
|
|
24
44
|
|
|
25
45
|
// use solver to reverse function, slow but hey - it works
|
|
26
|
-
let temperature;
|
|
46
|
+
let temperature = 0;
|
|
27
47
|
|
|
28
48
|
const epsilon = 0.4;
|
|
29
49
|
|
|
30
|
-
|
|
31
|
-
let maxTemperature = 40000;
|
|
32
|
-
|
|
50
|
+
// binary search
|
|
33
51
|
while (maxTemperature - minTemperature > epsilon) {
|
|
34
52
|
|
|
35
53
|
temperature = (maxTemperature + minTemperature) * 0.5;
|
|
36
54
|
|
|
37
55
|
kelvin_to_rgb(scratch_rgb, 0, temperature);
|
|
38
56
|
|
|
39
|
-
const
|
|
57
|
+
const actual_b = scratch_rgb[2];
|
|
58
|
+
const actual_r = scratch_rgb[0];
|
|
59
|
+
|
|
60
|
+
// prevent division by 0
|
|
61
|
+
const safe_r = Math.max(1e-7, actual_r);
|
|
40
62
|
|
|
41
|
-
|
|
63
|
+
const br = actual_b / safe_r;
|
|
64
|
+
|
|
65
|
+
if (br >= expected_blue_red_ratio) {
|
|
42
66
|
maxTemperature = temperature;
|
|
43
67
|
} else {
|
|
44
68
|
minTemperature = temperature;
|
|
45
69
|
}
|
|
70
|
+
|
|
46
71
|
}
|
|
47
72
|
|
|
48
73
|
return Math.round(temperature);
|