Skip to content

Commit f0e7d5e

Browse files
Nedunchezhiyan-MMugen87
andauthored
ColorUtils: Add setKelvin(). (#33381)
Co-authored-by: Michael Herzog <michael.herzog@human-interactive.org>
1 parent 6f4f8a8 commit f0e7d5e

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

examples/jsm/utils/ColorUtils.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { MathUtils, SRGBColorSpace } from 'three';
2+
3+
/**
4+
* @module ColorUtils
5+
* @three_import import * as ColorUtils from 'three/addons/utils/ColorUtils.js';
6+
*/
7+
8+
/**
9+
* Sets the given color from a color temperature in Kelvin.
10+
*
11+
* Converts a correlated color temperature (CTT) to an approximate sRGB color
12+
* using Tanner Helland's algorithm. Useful for physically-based lighting
13+
* setups — e.g. candle flame (~1900K), tungsten bulb (~3200K), daylight
14+
* (~6500K), or clear blue sky (~10000K). Values outside [1000, 40000] are
15+
* clamped.
16+
*
17+
* Reference: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
18+
*
19+
* @param {Color} color - The color to set.
20+
* @param {number} kelvin - Color temperature in Kelvin. Clamped to [1000, 40000].
21+
* @return {Color} The updated color.
22+
*/
23+
function setKelvin( color, kelvin ) {
24+
25+
// Algorithm by Tanner Helland (2012). Inputs are divided by 100.
26+
const temp = MathUtils.clamp( kelvin, 1000, 40000 ) / 100;
27+
28+
let r, g, b;
29+
30+
// Red channel
31+
if ( temp <= 66 ) {
32+
33+
r = 255;
34+
35+
} else {
36+
37+
r = 329.698727446 * Math.pow( temp - 60, - 0.1332047592 );
38+
39+
}
40+
41+
// Green channel
42+
if ( temp <= 66 ) {
43+
44+
g = 99.4708025861 * Math.log( temp ) - 161.1195681661;
45+
46+
} else {
47+
48+
g = 288.1221695283 * Math.pow( temp - 60, - 0.0755148492 );
49+
50+
}
51+
52+
// Blue channel
53+
if ( temp >= 66 ) {
54+
55+
b = 255;
56+
57+
} else if ( temp <= 19 ) {
58+
59+
b = 0;
60+
61+
} else {
62+
63+
b = 138.5177312231 * Math.log( temp - 10 ) - 305.0447927307;
64+
65+
}
66+
67+
return color.setRGB(
68+
MathUtils.clamp( r, 0, 255 ) / 255,
69+
MathUtils.clamp( g, 0, 255 ) / 255,
70+
MathUtils.clamp( b, 0, 255 ) / 255,
71+
SRGBColorSpace
72+
);
73+
74+
}
75+
76+
export { setKelvin };
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Color } from '../../../../src/math/Color.js';
2+
import { ColorManagement } from '../../../../src/math/ColorManagement.js';
3+
import * as ColorUtils from '../../../../examples/jsm/utils/ColorUtils.js';
4+
5+
export default QUnit.module( 'Addons', () => {
6+
7+
QUnit.module( 'Utils', () => {
8+
9+
QUnit.module( 'ColorUtils', () => {
10+
11+
const colorManagementEnabled = ColorManagement.enabled;
12+
13+
QUnit.testDone( () => {
14+
15+
ColorManagement.enabled = colorManagementEnabled;
16+
17+
} );
18+
19+
QUnit.test( 'setKelvin', ( assert ) => {
20+
21+
ColorManagement.enabled = false; // TODO: Update and enable.
22+
23+
const c = new Color();
24+
25+
// ~1900K candle flame — warm reddish-orange, no blue
26+
ColorUtils.setKelvin( c, 1900 );
27+
assert.ok( c.r > c.g && c.g > c.b && c.b === 0, 'Candle (~1900K): r > g > b, b = 0' );
28+
29+
// ~6500K daylight — roughly white, all channels near 1
30+
ColorUtils.setKelvin( c, 6500 );
31+
assert.ok( c.r > 0.9 && c.g > 0.9 && c.b > 0.9, 'Daylight (~6500K): all channels near 1' );
32+
33+
// clamping: below 1000K should equal 1000K
34+
const atMin = ColorUtils.setKelvin( new Color(), 1000 );
35+
ColorUtils.setKelvin( c, 500 );
36+
assert.ok( c.equals( atMin ), 'Values below 1000K are clamped to 1000K' );
37+
38+
// clamping: above 40000K should equal 40000K
39+
const atMax = ColorUtils.setKelvin( new Color(), 40000 );
40+
ColorUtils.setKelvin( c, 50000 );
41+
assert.ok( c.equals( atMax ), 'Values above 40000K are clamped to 40000K' );
42+
43+
// ~10000K cool blue sky — blue channel above red
44+
ColorUtils.setKelvin( c, 10000 );
45+
assert.ok( c.b > c.r, 'Blue sky (~10000K): b > r' );
46+
47+
} );
48+
49+
} );
50+
51+
} );
52+
53+
} );

test/unit/three.addons.unit.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
//addons/utils
33
import './addons/utils/BufferGeometryUtils.tests.js';
4+
import './addons/utils/ColorUtils.tests.js';
45
import './addons/math/ColorSpaces.tests.js';
56
import './addons/curves/NURBSCurve.tests.js';
67
import './addons/loaders/HDRLoader.tests.js';

0 commit comments

Comments
 (0)