diff --git a/examples/files.json b/examples/files.json
index cbc164b4216590..b72521ae65d266 100644
--- a/examples/files.json
+++ b/examples/files.json
@@ -213,6 +213,7 @@
"webgl_sprites",
"webgl_test_memory",
"webgl_test_memory2",
+ "webgl_test_wide_gamut",
"webgl_tonemapping",
"webgl_video_kinect",
"webgl_video_panorama_equirectangular",
diff --git a/examples/jsm/capabilities/WebGL.js b/examples/jsm/capabilities/WebGL.js
index 08666feb103f91..2abf2614fccbc0 100644
--- a/examples/jsm/capabilities/WebGL.js
+++ b/examples/jsm/capabilities/WebGL.js
@@ -30,6 +30,23 @@ class WebGL {
}
+ static isColorSpaceAvailable( colorSpace ) {
+
+ try {
+
+ const canvas = document.createElement( 'canvas' );
+ const ctx = window.WebGL2RenderingContext && canvas.getContext( 'webgl2' );
+ ctx.drawingBufferColorSpace = colorSpace;
+ return ctx.drawingBufferColorSpace === colorSpace; // deepscan-disable-line SAME_OPERAND_VALUE
+
+ } catch ( e ) {
+
+ return false;
+
+ }
+
+ }
+
static getWebGLErrorMessage() {
return this.getErrorMessage( 1 );
diff --git a/examples/jsm/postprocessing/OutputPass.js b/examples/jsm/postprocessing/OutputPass.js
index d2207624d9ed95..09e36614b25325 100644
--- a/examples/jsm/postprocessing/OutputPass.js
+++ b/examples/jsm/postprocessing/OutputPass.js
@@ -1,11 +1,12 @@
import {
+ ColorManagement,
RawShaderMaterial,
UniformsUtils,
LinearToneMapping,
ReinhardToneMapping,
CineonToneMapping,
ACESFilmicToneMapping,
- SRGBColorSpace
+ SRGBTransfer
} from 'three';
import { Pass, FullScreenQuad } from './Pass.js';
import { OutputShader } from '../shaders/OutputShader.js';
@@ -51,7 +52,7 @@ class OutputPass extends Pass {
this.material.defines = {};
- if ( this._outputColorSpace == SRGBColorSpace ) this.material.defines.SRGB_COLOR_SPACE = '';
+ if ( ColorManagement.getTransfer( this._outputColorSpace ) === SRGBTransfer ) this.material.defines.SRGB_TRANSFER = '';
if ( this._toneMapping === LinearToneMapping ) this.material.defines.LINEAR_TONE_MAPPING = '';
else if ( this._toneMapping === ReinhardToneMapping ) this.material.defines.REINHARD_TONE_MAPPING = '';
diff --git a/examples/jsm/shaders/GammaCorrectionShader.js b/examples/jsm/shaders/GammaCorrectionShader.js
index ca0732605d92f8..719960497b6008 100644
--- a/examples/jsm/shaders/GammaCorrectionShader.js
+++ b/examples/jsm/shaders/GammaCorrectionShader.js
@@ -34,7 +34,7 @@ const GammaCorrectionShader = {
vec4 tex = texture2D( tDiffuse, vUv );
- gl_FragColor = LinearTosRGB( tex );
+ gl_FragColor = sRGBTransferOETF( tex );
}`
diff --git a/examples/jsm/shaders/OutputShader.js b/examples/jsm/shaders/OutputShader.js
index d15c4dd143aef8..cf7a18ae7f9de8 100644
--- a/examples/jsm/shaders/OutputShader.js
+++ b/examples/jsm/shaders/OutputShader.js
@@ -65,9 +65,9 @@ const OutputShader = {
// color space
- #ifdef SRGB_COLOR_SPACE
+ #ifdef SRGB_TRANSFER
- gl_FragColor = LinearTosRGB( gl_FragColor );
+ gl_FragColor = sRGBTransferOETF( gl_FragColor );
#endif
diff --git a/examples/screenshots/webgl_test_wide_gamut.jpg b/examples/screenshots/webgl_test_wide_gamut.jpg
new file mode 100644
index 00000000000000..a1250f0ee67f13
Binary files /dev/null and b/examples/screenshots/webgl_test_wide_gamut.jpg differ
diff --git a/examples/textures/wide_gamut/logo_p3.png b/examples/textures/wide_gamut/logo_p3.png
new file mode 100644
index 00000000000000..20d97bc59106b3
Binary files /dev/null and b/examples/textures/wide_gamut/logo_p3.png differ
diff --git a/examples/textures/wide_gamut/logo_srgb.png b/examples/textures/wide_gamut/logo_srgb.png
new file mode 100644
index 00000000000000..4dfc4d1a3743a9
Binary files /dev/null and b/examples/textures/wide_gamut/logo_srgb.png differ
diff --git a/examples/webgl_test_wide_gamut.html b/examples/webgl_test_wide_gamut.html
new file mode 100644
index 00000000000000..641c80685d88e6
--- /dev/null
+++ b/examples/webgl_test_wide_gamut.html
@@ -0,0 +1,232 @@
+
+
+
+ three.js webgl - test - wide gamut
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/constants.js b/src/constants.js
index d30a7713755a3a..aab485cb35f31c 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -158,6 +158,12 @@ export const LinearSRGBColorSpace = 'srgb-linear';
export const DisplayP3ColorSpace = 'display-p3';
export const LinearDisplayP3ColorSpace = 'display-p3-linear';
+export const LinearTransfer = 'linear';
+export const SRGBTransfer = 'srgb';
+
+export const Rec709Primaries = 'rec709';
+export const P3Primaries = 'p3';
+
export const ZeroStencilOp = 0;
export const KeepStencilOp = 7680;
export const ReplaceStencilOp = 7681;
diff --git a/src/math/ColorManagement.js b/src/math/ColorManagement.js
index d15d3d3539c98e..296334d2929ac4 100644
--- a/src/math/ColorManagement.js
+++ b/src/math/ColorManagement.js
@@ -1,18 +1,6 @@
-import { SRGBColorSpace, LinearSRGBColorSpace, DisplayP3ColorSpace, } from '../constants.js';
+import { SRGBColorSpace, LinearSRGBColorSpace, DisplayP3ColorSpace, LinearDisplayP3ColorSpace, Rec709Primaries, P3Primaries, SRGBTransfer, LinearTransfer, NoColorSpace, } from '../constants.js';
import { Matrix3 } from './Matrix3.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;
-
-}
-
/**
* Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping
* or clipping. Based on W3C specifications for sRGB and Display P3,
@@ -25,50 +13,57 @@ export function LinearToSRGB( c ) {
* - http://www.russellcottrell.com/photo/matrixCalculator.htm
*/
-const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().fromArray( [
- 0.8224621, 0.0331941, 0.0170827,
- 0.1775380, 0.9668058, 0.0723974,
- - 0.0000001, 0.0000001, 0.9105199
-] );
-
-const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().fromArray( [
- 1.2249401, - 0.0420569, - 0.0196376,
- - 0.2249404, 1.0420571, - 0.0786361,
- 0.0000001, 0.0000000, 1.0982735
-] );
-
-function DisplayP3ToLinearSRGB( color ) {
+const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set(
+ 0.8224621, 0.177538, 0.0,
+ 0.0331941, 0.9668058, 0.0,
+ 0.0170827, 0.0723974, 0.9105199,
+);
- // Display P3 uses the sRGB transfer functions
- return color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB );
+const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set(
+ 1.2249401, - 0.2249404, 0.0,
+ - 0.0420569, 1.0420571, 0.0,
+ - 0.0196376, - 0.0786361, 1.0982735
+);
-}
-
-function LinearSRGBToDisplayP3( color ) {
-
- // Display P3 uses the sRGB transfer functions
- return color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB();
-
-}
-
-// Conversions from