瀏覽代碼

Color: Add 'colorSpace' argument for getters/setters (#23392)

* ColorManagement: Initial commit

* Color: revert to original CSS whitespace.

* Constants: NonColorData → NoColorSpace
Don McCurdy 3 年之前
父節點
當前提交
5c94e668c5
共有 6 個文件被更改,包括 161 次插入41 次删除
  1. 9 9
      docs/api/en/math/Color.html
  2. 9 9
      docs/api/zh/math/Color.html
  3. 1 0
      src/Three.js
  4. 5 0
      src/constants.js
  5. 63 23
      src/math/Color.js
  6. 74 0
      src/math/ColorManagement.js

+ 9 - 9
docs/api/en/math/Color.html

@@ -161,13 +161,13 @@ const color7 = new THREE.Color( 1, 0, 0 );
 		Sets this color's components from the [page:BufferAttribute attribute].
 		Sets this color's components from the [page:BufferAttribute attribute].
 		</p>
 		</p>
 
 
-		<h3>[method:Integer getHex]()</h3>
+		<h3>[method:Integer getHex]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>Returns the hexadecimal value of this color.</p>
 		<p>Returns the hexadecimal value of this color.</p>
 
 
-		<h3>[method:String getHexString]()</h3>
+		<h3>[method:String getHexString]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').</p>
 		<p>Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').</p>
 
 
-		<h3>[method:Object getHSL]( [param:Object target] )</h3>
+		<h3>[method:Object getHSL]( [param:Object target], [param:string colorSpace] = LinearSRGBColorSpace )</h3>
 		<p>
 		<p>
 			[page:Object target] — the result will be copied into this Object. Adds h, s and l keys to the object (if not already present).<br /><br />
 			[page:Object target] — the result will be copied into this Object. Adds h, s and l keys to the object (if not already present).<br /><br />
 
 
@@ -180,7 +180,7 @@ const color7 = new THREE.Color( 1, 0, 0 );
 
 
 		</p>
 		</p>
 
 
-		<h3>[method:String getStyle]()</h3>
+		<h3>[method:String getStyle]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>Returns the value of this color as a CSS style string. Example: 'rgb(255,0,0)'.</p>
 		<p>Returns the value of this color as a CSS style string. Example: 'rgb(255,0,0)'.</p>
 
 
 		<h3>[method:this lerp]( [param:Color color], [param:Float alpha] ) </h3>
 		<h3>[method:this lerp]( [param:Color color], [param:Float alpha] ) </h3>
@@ -237,14 +237,14 @@ const color7 = new THREE.Color( 1, 0, 0 );
 		Delegates to [page:.copy], [page:.setStyle], or [page:.setHex] depending on input type.
 		Delegates to [page:.copy], [page:.setStyle], or [page:.setHex] depending on input type.
 		</p>
 		</p>
 
 
-		<h3>[method:this setHex]( [param:Integer hex] ) </h3>
+		<h3>[method:this setHex]( [param:Integer hex], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Integer hex] — [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] format.<br /><br />
 		[page:Integer hex] — [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] format.<br /><br />
 
 
 		Sets this color from a hexadecimal value.
 		Sets this color from a hexadecimal value.
 		</p>
 		</p>
 
 
-		<h3>[method:this setHSL]( [param:Float h], [param:Float s], [param:Float l] ) </h3>
+		<h3>[method:this setHSL]( [param:Float h], [param:Float s], [param:Float l], [param:string colorSpace] = LinearSRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Float h] — hue value between 0.0 and 1.0 <br />
 		[page:Float h] — hue value between 0.0 and 1.0 <br />
 		[page:Float s] — saturation value between 0.0 and 1.0 <br />
 		[page:Float s] — saturation value between 0.0 and 1.0 <br />
@@ -253,7 +253,7 @@ const color7 = new THREE.Color( 1, 0, 0 );
 		Sets color from HSL values.
 		Sets color from HSL values.
 		</p>
 		</p>
 
 
-		<h3>[method:this setRGB]( [param:Float r], [param:Float g], [param:Float b] ) </h3>
+		<h3>[method:this setRGB]( [param:Float r], [param:Float g], [param:Float b], [param:string colorSpace] = LinearSRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Float r] — Red channel value between 0.0 and 1.0.<br />
 		[page:Float r] — Red channel value between 0.0 and 1.0.<br />
 		[page:Float g] — Green channel value between 0.0 and 1.0.<br />
 		[page:Float g] — Green channel value between 0.0 and 1.0.<br />
@@ -269,7 +269,7 @@ const color7 = new THREE.Color( 1, 0, 0 );
 		Sets all three color components to the value [page:Float scalar].
 		Sets all three color components to the value [page:Float scalar].
 		</p>
 		</p>
 
 
-		<h3>[method:this setStyle]( [param:String style] ) </h3>
+		<h3>[method:this setStyle]( [param:String style], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:String style] — color as a CSS-style string.<br /><br />
 		[page:String style] — color as a CSS-style string.<br /><br />
 
 
@@ -288,7 +288,7 @@ const color7 = new THREE.Color( 1, 0, 0 );
 		Note that for X11 color names, multiple words such as Dark Orange become the string 'darkorange'.
 		Note that for X11 color names, multiple words such as Dark Orange become the string 'darkorange'.
 		</p>
 		</p>
 
 
-		<h3>[method:this setColorName]( [param:String style] ) </h3>
+		<h3>[method:this setColorName]( [param:String style], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:String style] — color name ( from [link:https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart X11 color names] ).<br /><br />
 		[page:String style] — color name ( from [link:https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart X11 color names] ).<br /><br />
 
 

+ 9 - 9
docs/api/zh/math/Color.html

@@ -161,13 +161,13 @@
 		根据参数 [page:BufferAttribute attribute] 设置该颜色。
 		根据参数 [page:BufferAttribute attribute] 设置该颜色。
 		</p>
 		</p>
 
 
-		<h3>[method:Integer getHex]()</h3>
+		<h3>[method:Integer getHex]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>返回此颜色的十六进制值。</p>
 		<p>返回此颜色的十六进制值。</p>
 
 
-		<h3>[method:String getHexString]()</h3>
+		<h3>[method:String getHexString]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>将此颜色的十六进制值作为字符串返回 (例如, 'FFFFFF')。</p>
 		<p>将此颜色的十六进制值作为字符串返回 (例如, 'FFFFFF')。</p>
 
 
-		<h3>[method:Object getHSL]( [param:Object target] )</h3>
+		<h3>[method:Object getHSL]( [param:Object target], [param:string colorSpace] = LinearSRGBColorSpace )</h3>
 		<p>
 		<p>
 			[page:Object target] — 结果将复制到这个对象中。向对象添加h、s和l键(如果不存在)。<br /><br />
 			[page:Object target] — 结果将复制到这个对象中。向对象添加h、s和l键(如果不存在)。<br /><br />
 
 
@@ -179,7 +179,7 @@
 
 
 		</p>
 		</p>
 
 
-		<h3>[method:String getStyle]()</h3>
+		<h3>[method:String getStyle]( [param:string colorSpace] = SRGBColorSpace )</h3>
 		<p>以CSS样式字符串的形式返回该颜色的值。例如:“rgb(255,0,0)”。</p>
 		<p>以CSS样式字符串的形式返回该颜色的值。例如:“rgb(255,0,0)”。</p>
 
 
 		<h3>[method:this lerp]( [param:Color color], [param:Float alpha] ) </h3>
 		<h3>[method:this lerp]( [param:Color color], [param:Float alpha] ) </h3>
@@ -231,7 +231,7 @@
 		根据输入类型,将会委托给 [page:.copy], [page:.setStyle], 或者 [page:.setHex] 函数处理。
 		根据输入类型,将会委托给 [page:.copy], [page:.setStyle], 或者 [page:.setHex] 函数处理。
 		</p>
 		</p>
 
 
-		<h3>[method:this setHex]( [param:Integer hex] ) </h3>
+		<h3>[method:this setHex]( [param:Integer hex], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Integer hex] — [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] 格式。<br /><br />
 		[page:Integer hex] — [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] 格式。<br /><br />
 
 
@@ -239,7 +239,7 @@
 
 
 		</p>
 		</p>
 
 
-		<h3>[method:this setHSL]( [param:Float h], [param:Float s], [param:Float l] ) </h3>
+		<h3>[method:this setHSL]( [param:Float h], [param:Float s], [param:Float l], [param:string colorSpace] = LinearSRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Float h] — 色相值处于0到1之间。hue value between 0.0 and 1.0 <br />
 		[page:Float h] — 色相值处于0到1之间。hue value between 0.0 and 1.0 <br />
 		[page:Float s] — 饱和度值处于0到1之间。<br />
 		[page:Float s] — 饱和度值处于0到1之间。<br />
@@ -248,7 +248,7 @@
 		采用HLS值设置此颜色。
 		采用HLS值设置此颜色。
 		</p>
 		</p>
 
 
-		<h3>[method:this setRGB]( [param:Float r], [param:Float g], [param:Float b] ) </h3>
+		<h3>[method:this setRGB]( [param:Float r], [param:Float g], [param:Float b], [param:string colorSpace] = LinearSRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:Float r] — 红色通道的值在0到1之间。<br />
 		[page:Float r] — 红色通道的值在0到1之间。<br />
 		[page:Float g] — 绿色通道的值在0到1之间。<br />
 		[page:Float g] — 绿色通道的值在0到1之间。<br />
@@ -264,7 +264,7 @@
 		将颜色的RGB值都设为该 [page:Float scalar] 的值。
 		将颜色的RGB值都设为该 [page:Float scalar] 的值。
 		</p>
 		</p>
 
 
-		<h3>[method:this setStyle]( [param:String style] ) </h3>
+		<h3>[method:this setStyle]( [param:String style], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:String style] — 颜色css样式的字符串<br /><br />
 		[page:String style] — 颜色css样式的字符串<br /><br />
 
 
@@ -283,7 +283,7 @@
 		注意,对于X11颜色名称,多个单词(如暗橙色)变成字符串“darkorange”。
 		注意,对于X11颜色名称,多个单词(如暗橙色)变成字符串“darkorange”。
 		</p>
 		</p>
 
 
-		<h3>[method:this setColorName]( [param:String style] ) </h3>
+		<h3>[method:this setColorName]( [param:String style], [param:string colorSpace] = SRGBColorSpace ) </h3>
 		<p>
 		<p>
 		[page:String style] — 颜色名字的英文单词 ( 具体请查阅 [link:https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart X11 color names] )<br /><br />
 		[page:String style] — 颜色名字的英文单词 ( 具体请查阅 [link:https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart X11 color names] )<br /><br />
 
 

+ 1 - 0
src/Three.js

@@ -127,6 +127,7 @@ export { Vector3 } from './math/Vector3.js';
 export { Vector2 } from './math/Vector2.js';
 export { Vector2 } from './math/Vector2.js';
 export { Quaternion } from './math/Quaternion.js';
 export { Quaternion } from './math/Quaternion.js';
 export { Color } from './math/Color.js';
 export { Color } from './math/Color.js';
+export { ColorManagement } from './math/ColorManagement.js';
 export { SphericalHarmonics3 } from './math/SphericalHarmonics3.js';
 export { SphericalHarmonics3 } from './math/SphericalHarmonics3.js';
 export { SpotLightHelper } from './helpers/SpotLightHelper.js';
 export { SpotLightHelper } from './helpers/SpotLightHelper.js';
 export { SkeletonHelper } from './helpers/SkeletonHelper.js';
 export { SkeletonHelper } from './helpers/SkeletonHelper.js';

+ 5 - 0
src/constants.js

@@ -145,6 +145,11 @@ export const RGBADepthPacking = 3201;
 export const TangentSpaceNormalMap = 0;
 export const TangentSpaceNormalMap = 0;
 export const ObjectSpaceNormalMap = 1;
 export const ObjectSpaceNormalMap = 1;
 
 
+// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available.
+export const NoColorSpace = '';
+export const SRGBColorSpace = 'srgb';
+export const LinearSRGBColorSpace = 'srgb-linear';
+
 export const ZeroStencilOp = 0;
 export const ZeroStencilOp = 0;
 export const KeepStencilOp = 7680;
 export const KeepStencilOp = 7680;
 export const ReplaceStencilOp = 7681;
 export const ReplaceStencilOp = 7681;

+ 63 - 23
src/math/Color.js

@@ -1,4 +1,6 @@
 import { clamp, euclideanModulo, lerp } from './MathUtils.js';
 import { clamp, euclideanModulo, lerp } from './MathUtils.js';
+import { ColorManagement, SRGBToLinear, LinearToSRGB } from './ColorManagement.js';
+import { SRGBColorSpace, LinearSRGBColorSpace } from '../constants.js';
 
 
 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
 	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
 	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
@@ -25,6 +27,7 @@ const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua'
 	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
 	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
 	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
 	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
 
 
+const _rgb = { r: 0, g: 0, b: 0 };
 const _hslA = { h: 0, s: 0, l: 0 };
 const _hslA = { h: 0, s: 0, l: 0 };
 const _hslB = { h: 0, s: 0, l: 0 };
 const _hslB = { h: 0, s: 0, l: 0 };
 
 
@@ -39,15 +42,13 @@ function hue2rgb( p, q, t ) {
 
 
 }
 }
 
 
-function SRGBToLinear( c ) {
+function toComponents( source, target ) {
 
 
-	return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
+	target.r = source.r;
+	target.g = source.g;
+	target.b = source.b;
 
 
-}
-
-function LinearToSRGB( c ) {
-
-	return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
+	return target;
 
 
 }
 }
 
 
@@ -96,7 +97,7 @@ class Color {
 
 
 	}
 	}
 
 
-	setHex( hex ) {
+	setHex( hex, colorSpace = SRGBColorSpace ) {
 
 
 		hex = Math.floor( hex );
 		hex = Math.floor( hex );
 
 
@@ -104,21 +105,25 @@ class Color {
 		this.g = ( hex >> 8 & 255 ) / 255;
 		this.g = ( hex >> 8 & 255 ) / 255;
 		this.b = ( hex & 255 ) / 255;
 		this.b = ( hex & 255 ) / 255;
 
 
+		ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 		return this;
 		return this;
 
 
 	}
 	}
 
 
-	setRGB( r, g, b ) {
+	setRGB( r, g, b, colorSpace = LinearSRGBColorSpace ) {
 
 
 		this.r = r;
 		this.r = r;
 		this.g = g;
 		this.g = g;
 		this.b = b;
 		this.b = b;
 
 
+		ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 		return this;
 		return this;
 
 
 	}
 	}
 
 
-	setHSL( h, s, l ) {
+	setHSL( h, s, l, colorSpace = LinearSRGBColorSpace ) {
 
 
 		// h,s,l ranges are in 0.0 - 1.0
 		// h,s,l ranges are in 0.0 - 1.0
 		h = euclideanModulo( h, 1 );
 		h = euclideanModulo( h, 1 );
@@ -140,11 +145,13 @@ class Color {
 
 
 		}
 		}
 
 
+		ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 		return this;
 		return this;
 
 
 	}
 	}
 
 
-	setStyle( style ) {
+	setStyle( style, colorSpace = SRGBColorSpace ) {
 
 
 		function handleAlpha( string ) {
 		function handleAlpha( string ) {
 
 
@@ -181,6 +188,8 @@ class Color {
 						this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
 						this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
 						this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
 						this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
 
 
+						ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 						handleAlpha( color[ 4 ] );
 						handleAlpha( color[ 4 ] );
 
 
 						return this;
 						return this;
@@ -194,6 +203,8 @@ class Color {
 						this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
 						this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
 						this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
 						this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
 
 
+						ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 						handleAlpha( color[ 4 ] );
 						handleAlpha( color[ 4 ] );
 
 
 						return this;
 						return this;
@@ -214,7 +225,7 @@ class Color {
 
 
 						handleAlpha( color[ 4 ] );
 						handleAlpha( color[ 4 ] );
 
 
-						return this.setHSL( h, s, l );
+						return this.setHSL( h, s, l, colorSpace );
 
 
 					}
 					}
 
 
@@ -236,6 +247,8 @@ class Color {
 				this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
 				this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
 				this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
 				this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
 
 
+				ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 				return this;
 				return this;
 
 
 			} else if ( size === 6 ) {
 			} else if ( size === 6 ) {
@@ -245,6 +258,8 @@ class Color {
 				this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
 				this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
 				this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
 				this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
 
 
+				ColorManagement.toWorkingColorSpace( this, colorSpace );
+
 				return this;
 				return this;
 
 
 			}
 			}
@@ -253,7 +268,7 @@ class Color {
 
 
 		if ( style && style.length > 0 ) {
 		if ( style && style.length > 0 ) {
 
 
-			return this.setColorName( style );
+			return this.setColorName( style, colorSpace );
 
 
 		}
 		}
 
 
@@ -261,7 +276,7 @@ class Color {
 
 
 	}
 	}
 
 
-	setColorName( style ) {
+	setColorName( style, colorSpace = SRGBColorSpace ) {
 
 
 		// color keywords
 		// color keywords
 		const hex = _colorKeywords[ style.toLowerCase() ];
 		const hex = _colorKeywords[ style.toLowerCase() ];
@@ -269,7 +284,7 @@ class Color {
 		if ( hex !== undefined ) {
 		if ( hex !== undefined ) {
 
 
 			// red
 			// red
-			this.setHex( hex );
+			this.setHex( hex, colorSpace );
 
 
 		} else {
 		} else {
 
 
@@ -334,23 +349,27 @@ class Color {
 
 
 	}
 	}
 
 
-	getHex() {
+	getHex( colorSpace = SRGBColorSpace ) {
+
+		ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
 
 
-		return clamp( this.r * 255, 0, 255 ) << 16 ^ clamp( this.g * 255, 0, 255 ) << 8 ^ clamp( this.b * 255, 0, 255 ) << 0;
+		return clamp( _rgb.r * 255, 0, 255 ) << 16 ^ clamp( _rgb.g * 255, 0, 255 ) << 8 ^ clamp( _rgb.b * 255, 0, 255 ) << 0;
 
 
 	}
 	}
 
 
-	getHexString() {
+	getHexString( colorSpace = SRGBColorSpace ) {
 
 
-		return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
+		return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );
 
 
 	}
 	}
 
 
-	getHSL( target ) {
+	getHSL( target, colorSpace = LinearSRGBColorSpace ) {
 
 
 		// h,s,l ranges are in 0.0 - 1.0
 		// h,s,l ranges are in 0.0 - 1.0
 
 
-		const r = this.r, g = this.g, b = this.b;
+		ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
+
+		const r = _rgb.r, g = _rgb.g, b = _rgb.b;
 
 
 		const max = Math.max( r, g, b );
 		const max = Math.max( r, g, b );
 		const min = Math.min( r, g, b );
 		const min = Math.min( r, g, b );
@@ -389,9 +408,30 @@ class Color {
 
 
 	}
 	}
 
 
-	getStyle() {
+	getRGB( target, colorSpace = LinearSRGBColorSpace ) {
+
+		ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
+
+		target.r = _rgb.r;
+		target.g = _rgb.g;
+		target.b = _rgb.b;
+
+		return target;
+
+	}
+
+	getStyle( colorSpace = SRGBColorSpace ) {
+
+		ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
+
+		if ( colorSpace !== SRGBColorSpace ) {
+
+			// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
+			return `color(${ colorSpace } ${ _rgb.r } ${ _rgb.g } ${ _rgb.b })`;
+
+		}
 
 
-		return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
+		return `rgb(${( _rgb.r * 255 ) | 0},${( _rgb.g * 255 ) | 0},${( _rgb.b * 255 ) | 0})`;
 
 
 	}
 	}
 
 

+ 74 - 0
src/math/ColorManagement.js

@@ -0,0 +1,74 @@
+import { SRGBColorSpace, LinearSRGBColorSpace } from '../constants.js';
+
+export function SRGBToLinear( c ) {
+
+	return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
+
+}
+
+export function LinearToSRGB( c ) {
+
+	return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
+
+}
+
+// JavaScript RGB-to-RGB transforms, defined as
+// FN[InputColorSpace][OutputColorSpace] callback functions.
+const FN = {
+	[ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear },
+	[ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB },
+};
+
+export const ColorManagement = {
+
+	legacyMode: true,
+
+	get workingColorSpace() {
+
+		return LinearSRGBColorSpace;
+
+	},
+
+	set workingColorSpace( colorSpace ) {
+
+		console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' );
+
+	},
+
+	convert: function ( color, sourceColorSpace, targetColorSpace ) {
+
+		if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {
+
+			return color;
+
+		}
+
+		if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) {
+
+			const fn = FN[ sourceColorSpace ][ targetColorSpace ];
+
+			color.r = fn( color.r );
+			color.g = fn( color.g );
+			color.b = fn( color.b );
+
+			return color;
+
+		}
+
+		throw new Error( 'Unsupported color space conversion.' );
+
+	},
+
+	fromWorkingColorSpace: function ( color, targetColorSpace ) {
+
+		return this.convert( color, this.workingColorSpace, targetColorSpace );
+
+	},
+
+	toWorkingColorSpace: function ( color, sourceColorSpace ) {
+
+		return this.convert( color, sourceColorSpace, this.workingColorSpace );
+
+	},
+
+};