Преглед на файлове

WebGLRenderer: Remove inline sRGB decode. (#23129)

* WebGLRenderer: Remove inline sRGB decode.

* Update WebGLTextures.js

* VideoTexture: Use inline sRGB decode.

* WebGLTexture: Fix video textures with WebGL 1.
Michael Herzog преди 3 години
родител
ревизия
05fc79cd52
променени са 26 файла, в които са добавени 208 реда и са изтрити 214 реда
  1. 0 1
      examples/jsm/loaders/GLTFLoader.js
  2. 4 13
      examples/jsm/nodes/utils/ColorSpaceNode.js
  3. 5 22
      examples/jsm/renderers/nodes/display/ColorSpaceNode.js
  4. 0 2
      examples/jsm/utils/RoughnessMipmapper.js
  5. 0 1
      examples/webgl_lightprobe_cubecamera.html
  6. 10 9
      examples/webgl_materials_nodes.html
  7. 3 0
      src/constants.js
  8. 63 0
      src/extras/ImageUtils.js
  9. 7 69
      src/extras/PMREMGenerator.js
  10. 1 1
      src/math/Color.js
  11. 0 2
      src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl.js
  12. 0 4
      src/renderers/shaders/ShaderChunk/encodings_pars_fragment.glsl.js
  13. 0 2
      src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js
  14. 1 1
      src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl.js
  15. 1 1
      src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js
  16. 2 2
      src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js
  17. 10 3
      src/renderers/shaders/ShaderChunk/map_fragment.glsl.js
  18. 1 2
      src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl.js
  19. 1 3
      src/renderers/shaders/ShaderLib/background.glsl.js
  20. 1 3
      src/renderers/shaders/ShaderLib/equirect.glsl.js
  21. 1 1
      src/renderers/shaders/ShaderLib/meshbasic.glsl.js
  22. 0 1
      src/renderers/shaders/ShaderLib/meshmatcap.glsl.js
  23. 2 14
      src/renderers/webgl/WebGLProgram.js
  24. 6 51
      src/renderers/webgl/WebGLPrograms.js
  25. 69 5
      src/renderers/webgl/WebGLTextures.js
  26. 20 1
      src/renderers/webgl/WebGLUtils.js

+ 0 - 1
examples/jsm/loaders/GLTFLoader.js

@@ -1478,7 +1478,6 @@ class GLTFMeshStandardSGMaterial extends MeshStandardMaterial {
 			'vec3 specularFactor = specular;',
 			'#ifdef USE_SPECULARMAP',
 			'	vec4 texelSpecular = texture2D( specularMap, vUv );',
-			'	texelSpecular = sRGBToLinear( texelSpecular );',
 			'	// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
 			'	specularFactor *= texelSpecular.rgb;',
 			'#endif'

+ 4 - 13
examples/jsm/nodes/utils/ColorSpaceNode.js

@@ -57,9 +57,11 @@ class ColorSpaceNode extends TempNode {
 
 	}
 
-	fromDecoding( encoding ) {
+	fromDecoding() {
 
-		const components = ColorSpaceNode.getEncodingComponents( encoding );
+		// TODO: Remove fromDecoding()
+
+		const components = ColorSpaceNode.getEncodingComponents( LinearEncoding );
 
 		this.method = components[ 0 ] + 'ToLinear';
 		this.factor = components[ 1 ];
@@ -106,14 +108,6 @@ ColorSpaceNode.Nodes = ( function () {
 		}`
 	);
 
-	const sRGBToLinear = new FunctionNode( /* glsl */`
-		vec4 sRGBToLinear( in vec4 value ) {
-
-			return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );
-
-		}`
-	);
-
 	const LinearTosRGB = new FunctionNode( /* glsl */`
 		vec4 LinearTosRGB( in vec4 value ) {
 
@@ -124,15 +118,12 @@ ColorSpaceNode.Nodes = ( function () {
 
 	return {
 		LinearToLinear: LinearToLinear,
-		sRGBToLinear: sRGBToLinear,
 		LinearTosRGB: LinearTosRGB
 	};
 
 } )();
 
 ColorSpaceNode.LINEAR_TO_LINEAR = 'LinearToLinear';
-
-ColorSpaceNode.SRGB_TO_LINEAR = 'sRGBToLinear';
 ColorSpaceNode.LINEAR_TO_SRGB = 'LinearTosRGB';
 
 ColorSpaceNode.getEncodingComponents = function ( encoding ) {

+ 5 - 22
examples/jsm/renderers/nodes/display/ColorSpaceNode.js

@@ -1,7 +1,7 @@
 import TempNode from '../core/Node.js';
 import { ShaderNode,
 	vec3,
-	pow, mul, add, sub, mix, join,
+	pow, mul, sub, mix, join,
 	lessThanEqual } from '../ShaderNode.js';
 
 import { LinearEncoding, sRGBEncoding } from '../../../../../build/three.module.js';
@@ -12,22 +12,6 @@ export const LinearToLinear = new ShaderNode( ( inputs ) => {
 
 } );
 
-export const sRGBToLinear = new ShaderNode( ( inputs ) => {
-
-	const { value } = inputs;
-
-	const rgb = value.rgb;
-
-	const a = pow( add( mul( rgb, 0.9478672986 ), vec3( 0.0521327014 ) ), vec3( 2.4 ) );
-	const b = mul( rgb, 0.0773993808 );
-	const factor = vec3( lessThanEqual( rgb, vec3( 0.04045 ) ) );
-
-	const rgbResult = mix( a, b, factor );
-
-	return join( rgbResult.r, rgbResult.g, rgbResult.b, value.a );
-
-} );
-
 export const LinearTosRGB = new ShaderNode( ( inputs ) => {
 
 	const { value } = inputs;
@@ -46,7 +30,6 @@ export const LinearTosRGB = new ShaderNode( ( inputs ) => {
 
 const EncodingLib = {
 	LinearToLinear,
-	sRGBToLinear,
 	LinearTosRGB
 };
 
@@ -66,8 +49,6 @@ function getEncodingComponents( encoding ) {
 class ColorSpaceNode extends TempNode {
 
 	static LINEAR_TO_LINEAR = 'LinearToLinear';
-
-	static SRGB_TO_LINEAR = 'sRGBToLinear';
 	static LINEAR_TO_SRGB = 'LinearTosRGB';
 
 	constructor( method, node ) {
@@ -92,9 +73,11 @@ class ColorSpaceNode extends TempNode {
 
 	}
 
-	fromDecoding( encoding ) {
+	fromDecoding() {
 
-		const components = getEncodingComponents( encoding );
+		// TODO: Remove fromDecoding()
+
+		const components = getEncodingComponents( LinearEncoding );
 
 		this.method = components[ 0 ] + 'ToLinear';
 		this.factor = components[ 1 ];

+ 0 - 2
examples/jsm/utils/RoughnessMipmapper.js

@@ -184,8 +184,6 @@ function _getMipmapMaterial() {
 
 			#define ENVMAP_TYPE_CUBE_UV
 
-			vec4 envMapTexelToLinear( vec4 a ) { return a; }
-
 			#include <cube_uv_reflection_fragment>
 
 			float roughnessToVariance( float roughness ) {

+ 0 - 1
examples/webgl_lightprobe_cubecamera.html

@@ -43,7 +43,6 @@
 				camera.position.set( 0, 0, 30 );
 
 				const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, {
-					encoding: THREE.sRGBEncoding, // since gamma is applied during rendering, the cubeCamera renderTarget texture encoding must be sRGBEncoding
 					format: THREE.RGBAFormat
 				} );
 

+ 10 - 9
examples/webgl_materials_nodes.html

@@ -40,13 +40,13 @@
 			const library = {};
 			let serialized = false;
 			const textures = {
-				brick: { url: 'textures/brick_diffuse.jpg' },
-				grass: { url: 'textures/terrain/grasslight-big.jpg' },
-				grassNormal: { url: 'textures/terrain/grasslight-big-nm.jpg' },
-				decalDiffuse: { url: 'textures/decal/decal-diffuse.png' },
-				decalNormal: { url: 'textures/decal/decal-normal.jpg' },
-				cloud: { url: 'textures/lava/cloud.png' },
-				spherical: { url: 'textures/envmap.png' }
+				brick: { url: 'textures/brick_diffuse.jpg', encoding: THREE.sRGBEncoding },
+				grass: { url: 'textures/terrain/grasslight-big.jpg', encoding: THREE.sRGBEncoding },
+				grassNormal: { url: 'textures/terrain/grasslight-big-nm.jpg', encoding: THREE.LinearEncoding },
+				decalDiffuse: { url: 'textures/decal/decal-diffuse.png', encoding: THREE.sRGBEncoding },
+				decalNormal: { url: 'textures/decal/decal-normal.jpg', encoding: THREE.LinearEncoding },
+				cloud: { url: 'textures/lava/cloud.png', encoding: THREE.sRGBEncoding },
+				spherical: { url: 'textures/envmap.png', encoding: THREE.sRGBEncoding }
 			};
 
 			const param = { example: new URL( window.location.href ).searchParams.get( 'e' ) || 'mesh-standard' };
@@ -59,6 +59,7 @@
 
 					texture = textures[ name ].texture = new THREE.TextureLoader().load( textures[ name ].url );
 					texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+					texture.encoding = textures[ name ].encoding;
 
 					library[ texture.uuid ] = texture;
 
@@ -187,7 +188,7 @@
 					'basic / spherical-reflection': 'spherical-reflection',
 					'basic / standard': 'standard',
 					'basic / uv-transform': 'uv-transform',
-			
+
 					'adv / bias': 'bias',
 					'adv / camera-depth': 'camera-depth',
 					'adv / caustic': 'caustic',
@@ -215,7 +216,7 @@
 					'node / normal': 'node-normal',
 					'node / position': 'node-position',
 					'node / reflect': 'node-reflect',
-			
+
 					'misc / basic-material': 'basic-material',
 					'misc / custom-attribute': 'custom-attribute',
 					'misc / firefly': 'firefly',

+ 3 - 0
src/constants.js

@@ -177,3 +177,6 @@ export const StreamCopyUsage = 35042;
 
 export const GLSL1 = '100';
 export const GLSL3 = '300 es';
+
+export const _SRGBFormat = 1034; // fallback for WebGL 1
+export const _SRGBAFormat = 1035; // fallback for WebGL 1

+ 63 - 0
src/extras/ImageUtils.js

@@ -1,4 +1,5 @@
 import { createElementNS } from '../utils.js';
+import { SRGBToLinear } from '../math/Color.js';
 
 let _canvas;
 
@@ -61,6 +62,68 @@ class ImageUtils {
 
 	}
 
+	static sRGBToLinear( image ) {
+
+		if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
+			( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
+			( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
+
+			const canvas = createElementNS( 'canvas' );
+
+			canvas.width = image.width;
+			canvas.height = image.height;
+
+			const context = canvas.getContext( '2d' );
+			context.drawImage( image, 0, 0, image.width, image.height );
+
+			const imageData = context.getImageData( 0, 0, image.width, image.height );
+			const data = imageData.data;
+
+			for ( let i = 0; i < data.length; i ++ ) {
+
+				data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
+
+			}
+
+			context.putImageData( imageData, 0, 0 );
+
+			return canvas;
+
+		} else if ( image.data ) {
+
+			const data = image.data.slice( 0 );
+
+			for ( let i = 0; i < data.length; i ++ ) {
+
+				if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {
+
+					data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
+
+				} else {
+
+					// assuming float
+
+					data[ i ] = SRGBToLinear( data[ i ] );
+
+				}
+
+			}
+
+			return {
+				data: data,
+				width: image.width,
+				height: image.height
+			};
+
+		} else {
+
+			console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
+			return image;
+
+		}
+
+	}
+
 }
 
 export { ImageUtils };

+ 7 - 69
src/extras/PMREMGenerator.js

@@ -7,8 +7,6 @@ import {
 	NoToneMapping,
 	NoBlending,
 	RGBAFormat,
-	UnsignedByteType,
-	sRGBEncoding,
 	HalfFloatType
 } from '../constants.js';
 
@@ -42,11 +40,6 @@ const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
 // samples and exit early, but not recompile the shader.
 const MAX_SAMPLES = 20;
 
-const ENCODINGS = {
-	[ LinearEncoding ]: 0,
-	[ sRGBEncoding ]: 1
-};
-
 const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
 const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
 const _clearColor = /*@__PURE__*/ new Color();
@@ -335,20 +328,6 @@ class PMREMGenerator {
 
 	}
 
-	_setEncoding( uniform, texture ) {
-
-		if ( this._renderer.capabilities.isWebGL2 === true && texture.format === RGBAFormat && texture.type === UnsignedByteType && texture.encoding === sRGBEncoding ) {
-
-			uniform.value = ENCODINGS[ LinearEncoding ];
-
-		} else {
-
-			uniform.value = ENCODINGS[ texture.encoding ];
-
-		}
-
-	}
-
 	_textureToCubeUV( texture, cubeUVRenderTarget ) {
 
 		const renderer = this._renderer;
@@ -386,8 +365,6 @@ class PMREMGenerator {
 
 		}
 
-		this._setEncoding( uniforms[ 'inputEncoding' ], texture );
-
 		_setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
 
 		renderer.setRenderTarget( cubeUVRenderTarget );
@@ -662,8 +639,6 @@ function _getBlurShader( maxSamples ) {
 			uniform float mipInt;
 			uniform vec3 poleAxis;
 
-			${ _getEncodings() }
-
 			#define ENVMAP_TYPE_CUBE_UV
 			#include <cube_uv_reflection_fragment>
 
@@ -730,8 +705,7 @@ function _getEquirectShader() {
 
 		uniforms: {
 			'envMap': { value: null },
-			'texelSize': { value: texelSize },
-			'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }
+			'texelSize': { value: texelSize }
 		},
 
 		vertexShader: _getCommonVertexShader(),
@@ -746,8 +720,6 @@ function _getEquirectShader() {
 			uniform sampler2D envMap;
 			uniform vec2 texelSize;
 
-			${ _getEncodings() }
-
 			#include <common>
 
 			void main() {
@@ -759,13 +731,13 @@ function _getEquirectShader() {
 
 				vec2 f = fract( uv / texelSize - 0.5 );
 				uv -= f * texelSize;
-				vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
+				vec3 tl = texture2D ( envMap, uv ).rgb;
 				uv.x += texelSize.x;
-				vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
+				vec3 tr = texture2D ( envMap, uv ).rgb;
 				uv.y += texelSize.y;
-				vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
+				vec3 br = texture2D ( envMap, uv ).rgb;
 				uv.x -= texelSize.x;
-				vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
+				vec3 bl = texture2D ( envMap, uv ).rgb;
 
 				vec3 tm = mix( tl, tr, f.x );
 				vec3 bm = mix( bl, br, f.x );
@@ -791,8 +763,7 @@ function _getCubemapShader() {
 		name: 'CubemapToCubeUV',
 
 		uniforms: {
-			'envMap': { value: null },
-			'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }
+			'envMap': { value: null }
 		},
 
 		vertexShader: _getCommonVertexShader(),
@@ -806,11 +777,9 @@ function _getCubemapShader() {
 
 			uniform samplerCube envMap;
 
-			${ _getEncodings() }
-
 			void main() {
 
-				gl_FragColor = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) );
+				gl_FragColor = textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) );
 
 			}
 		`,
@@ -888,35 +857,4 @@ function _getCommonVertexShader() {
 
 }
 
-function _getEncodings() {
-
-	return /* glsl */`
-
-		uniform int inputEncoding;
-
-		#include <encodings_pars_fragment>
-
-		vec4 inputTexelToLinear( vec4 value ) {
-
-			if ( inputEncoding == 0 ) {
-
-				return value;
-
-			} else {
-
-				return sRGBToLinear( value );
-
-			}
-
-		}
-
-		vec4 envMapTexelToLinear( vec4 color ) {
-
-			return inputTexelToLinear( color );
-
-		}
-	`;
-
-}
-
 export { PMREMGenerator };

+ 1 - 1
src/math/Color.js

@@ -563,4 +563,4 @@ Color.prototype.r = 1;
 Color.prototype.g = 1;
 Color.prototype.b = 1;
 
-export { Color };
+export { Color, SRGBToLinear };

+ 0 - 2
src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl.js

@@ -3,8 +3,6 @@ export default /* glsl */`
 
 	vec4 emissiveColor = texture2D( emissiveMap, vUv );
 
-	emissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;
-
 	totalEmissiveRadiance *= emissiveColor.rgb;
 
 #endif

+ 0 - 4
src/renderers/shaders/ShaderChunk/encodings_pars_fragment.glsl.js

@@ -4,10 +4,6 @@ vec4 LinearToLinear( in vec4 value ) {
 	return value;
 }
 
-vec4 sRGBToLinear( in vec4 value ) {
-	return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );
-}
-
 vec4 LinearTosRGB( in vec4 value ) {
 	return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
 }

+ 0 - 2
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js

@@ -38,8 +38,6 @@ export default /* glsl */`
 
 		vec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );
 
-		envColor = envMapTexelToLinear( envColor );
-
 	#elif defined( ENVMAP_TYPE_CUBE_UV )
 
 		vec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );

+ 1 - 1
src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl.js

@@ -2,7 +2,7 @@ export default /* glsl */`
 #ifdef USE_LIGHTMAP
 
 	vec4 lightMapTexel = texture2D( lightMap, vUv2 );
-	vec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;
+	vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;
 
 	#ifndef PHYSICALLY_CORRECT_LIGHTS
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js

@@ -4,7 +4,7 @@ export default /* glsl */`
 	#ifdef USE_LIGHTMAP
 
 		vec4 lightMapTexel = texture2D( lightMap, vUv2 );
-		vec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;
+		vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;
 
 		#ifndef PHYSICALLY_CORRECT_LIGHTS
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js

@@ -24,7 +24,7 @@ material.roughness = min( material.roughness, 1.0 );
 
 		#ifdef USE_SPECULARCOLORMAP
 
-			specularColorFactor *= specularColorMapTexelToLinear( texture2D( specularColorMap, vUv ) ).rgb;
+			specularColorFactor *= texture2D( specularColorMap, vUv ).rgb;
 
 		#endif
 
@@ -79,7 +79,7 @@ material.roughness = min( material.roughness, 1.0 );
 
 	#ifdef USE_SHEENCOLORMAP
 
-		material.sheenColor *= sheenColorMapTexelToLinear( texture2D( sheenColorMap, vUv ) ).rgb;
+		material.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;
 
 	#endif
 

+ 10 - 3
src/renderers/shaders/ShaderChunk/map_fragment.glsl.js

@@ -1,10 +1,17 @@
 export default /* glsl */`
 #ifdef USE_MAP
 
-	vec4 texelColor = texture2D( map, vUv );
+	vec4 sampledDiffuseColor = texture2D( map, vUv );
 
-	texelColor = mapTexelToLinear( texelColor );
-	diffuseColor *= texelColor;
+	#ifdef DECODE_VIDEO_TEXTURE
+
+		// inline sRGB decode (TODO: Remove this code when https://crbug.com/1256340 is solved)
+
+		sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );
+
+	#endif
+
+	diffuseColor *= sampledDiffuseColor;
 
 #endif
 `;

+ 1 - 2
src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl.js

@@ -7,8 +7,7 @@ export default /* glsl */`
 
 #ifdef USE_MAP
 
-	vec4 mapTexel = texture2D( map, uv );
-	diffuseColor *= mapTexelToLinear( mapTexel );
+	diffuseColor *= texture2D( map, uv );
 
 #endif
 

+ 1 - 3
src/renderers/shaders/ShaderLib/background.glsl.js

@@ -18,9 +18,7 @@ varying vec2 vUv;
 
 void main() {
 
-	vec4 texColor = texture2D( t2D, vUv );
-
-	gl_FragColor = mapTexelToLinear( texColor );
+	gl_FragColor = texture2D( t2D, vUv );
 
 	#include <tonemapping_fragment>
 	#include <encodings_fragment>

+ 1 - 3
src/renderers/shaders/ShaderLib/equirect.glsl.js

@@ -26,9 +26,7 @@ void main() {
 
 	vec2 sampleUV = equirectUv( direction );
 
-	vec4 texColor = texture2D( tEquirect, sampleUV );
-
-	gl_FragColor = mapTexelToLinear( texColor );
+	gl_FragColor = texture2D( tEquirect, sampleUV );
 
 	#include <tonemapping_fragment>
 	#include <encodings_fragment>

+ 1 - 1
src/renderers/shaders/ShaderLib/meshbasic.glsl.js

@@ -87,7 +87,7 @@ void main() {
 	#ifdef USE_LIGHTMAP
 
 		vec4 lightMapTexel= texture2D( lightMap, vUv2 );
-		reflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;
+		reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity;
 
 	#else
 

+ 0 - 1
src/renderers/shaders/ShaderLib/meshmatcap.glsl.js

@@ -86,7 +86,6 @@ void main() {
 	#ifdef USE_MATCAP
 
 		vec4 matcapColor = texture2D( matcap, uv );
-		matcapColor = matcapTexelToLinear( matcapColor );
 
 	#else
 

+ 2 - 14
src/renderers/webgl/WebGLProgram.js

@@ -49,13 +49,6 @@ function getShaderErrors( gl, shader, type ) {
 
 }
 
-function getTexelDecodingFunction( functionName, encoding ) {
-
-	const components = getEncodingComponents( encoding );
-	return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
-
-}
-
 function getTexelEncodingFunction( functionName, encoding ) {
 
 	const components = getEncodingComponents( encoding );
@@ -625,6 +618,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
 			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
 
+			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
+
 			parameters.vertexTangents ? '#define USE_TANGENT' : '',
 			parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
 			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
@@ -662,13 +657,6 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.format === RGBFormat ? '#define OPAQUE' : '',
 
 			ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
-			parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
-			parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
-			parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
-			parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
-			parameters.specularColorMap ? getTexelDecodingFunction( 'specularColorMapTexelToLinear', parameters.specularColorMapEncoding ) : '',
-			parameters.sheenColorMap ? getTexelDecodingFunction( 'sheenColorMapTexelToLinear', parameters.sheenColorMapEncoding ) : '',
-			parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
 			getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
 
 			parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',

+ 6 - 51
src/renderers/webgl/WebGLPrograms.js

@@ -1,4 +1,4 @@
-import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, LinearEncoding, sRGBEncoding, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, RGBAFormat, UnsignedByteType } from '../../constants.js';
+import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, sRGBEncoding } from '../../constants.js';
 import { Layers } from '../../core/Layers.js';
 import { WebGLProgram } from './WebGLProgram.js';
 import { WebGLShaderCache } from './WebGLShaderCache.js';
@@ -72,41 +72,6 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 	}
 
-	function getTextureEncodingFromMap( map ) {
-
-		let encoding;
-
-		if ( map && map.isTexture ) {
-
-			encoding = map.encoding;
-
-		} else if ( map && map.isWebGLRenderTarget ) {
-
-			console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' );
-			encoding = map.texture.encoding;
-
-		} else {
-
-			encoding = LinearEncoding;
-
-		}
-
-		if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
-
-			encoding = LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
-
-		}
-
-		if ( map && map.isCompressedTexture ) {
-
-			encoding = LinearEncoding; // disable inline decode for sRGB compressed textures
-
-		}
-
-		return encoding;
-
-	}
-
 	function getParameters( material, lights, shadows, scene, object ) {
 
 		const fog = scene.fog;
@@ -183,25 +148,22 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
 
 			supportsVertexTextures: vertexTextures,
-			outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
+			outputEncoding: ( currentRenderTarget !== null ) ? currentRenderTarget.texture.encoding : renderer.outputEncoding,
 			map: !! material.map,
-			mapEncoding: getTextureEncodingFromMap( material.map ),
 			matcap: !! material.matcap,
-			matcapEncoding: getTextureEncodingFromMap( material.matcap ),
 			envMap: !! envMap,
 			envMapMode: envMap && envMap.mapping,
-			envMapEncoding: getTextureEncodingFromMap( envMap ),
 			envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
 			lightMap: !! material.lightMap,
-			lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
 			aoMap: !! material.aoMap,
 			emissiveMap: !! material.emissiveMap,
-			emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
 			bumpMap: !! material.bumpMap,
 			normalMap: !! material.normalMap,
 			objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
 			tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
 
+			decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ),
+
 			clearcoat: useClearcoat,
 			clearcoatMap: useClearcoat && !! material.clearcoatMap,
 			clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap,
@@ -213,7 +175,6 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			specularMap: !! material.specularMap,
 			specularIntensityMap: !! material.specularIntensityMap,
 			specularColorMap: !! material.specularColorMap,
-			specularColorMapEncoding: getTextureEncodingFromMap( material.specularColorMap ),
 
 			alphaMap: !! material.alphaMap,
 			alphaTest: useAlphaTest,
@@ -222,7 +183,6 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 			sheen: material.sheen > 0,
 			sheenColorMap: !! material.sheenColorMap,
-			sheenColorMapEncoding: getTextureEncodingFromMap( material.sheenColorMap ),
 			sheenRoughnessMap: !! material.sheenRoughnessMap,
 
 			transmission: material.transmission > 0,
@@ -346,12 +306,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 		array.push( parameters.precision );
 		array.push( parameters.outputEncoding );
-		array.push( parameters.mapEncoding );
-		array.push( parameters.matcapEncoding );
 		array.push( parameters.envMapMode );
-		array.push( parameters.envMapEncoding );
-		array.push( parameters.lightMapEncoding );
-		array.push( parameters.emissiveMapEncoding );
 		array.push( parameters.combine );
 		array.push( parameters.vertexUvs );
 		array.push( parameters.fogExp2 );
@@ -371,8 +326,6 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 		array.push( parameters.numClippingPlanes );
 		array.push( parameters.numClipIntersection );
 		array.push( parameters.format );
-		array.push( parameters.specularColorMapEncoding );
-		array.push( parameters.sheenColorMapEncoding );
 
 	}
 
@@ -492,6 +445,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			_programLayers.enable( 20 );
 		if ( parameters.sheenRoughnessMap )
 			_programLayers.enable( 21 );
+		if ( parameters.decodeVideoTexture )
+			_programLayers.enable( 22 );
 
 		array.push( _programLayers.mask );
 

+ 69 - 5
src/renderers/webgl/WebGLTextures.js

@@ -1,5 +1,6 @@
-import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, sRGBEncoding } from '../../constants.js';
+import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, sRGBEncoding, LinearEncoding, UnsignedByteType, _SRGBFormat, _SRGBAFormat } from '../../constants.js';
 import * as MathUtils from '../../math/MathUtils.js';
+import { ImageUtils } from '../../extras/ImageUtils.js';
 import { createElementNS } from '../../utils.js';
 
 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
@@ -130,7 +131,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 	}
 
-	function getInternalFormat( internalFormatName, glFormat, glType, encoding ) {
+	function getInternalFormat( internalFormatName, glFormat, glType, encoding, isVideoTexture = false ) {
 
 		if ( isWebGL2 === false ) return glFormat;
 
@@ -164,7 +165,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 			if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
 			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
-			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( encoding === sRGBEncoding ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( encoding === sRGBEncoding && isVideoTexture === false ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
 
 		}
 
@@ -550,13 +551,14 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 		_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, _gl.NONE );
 
 		const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
-		const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
+		let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
+		image = verifyColorSpace( texture, image );
 
 		const supportsMips = isPowerOfTwo( image ) || isWebGL2,
 			glFormat = utils.convert( texture.format, texture.encoding );
 
 		let glType = utils.convert( texture.type ),
-			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
+			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture );
 
 		setTextureParameters( textureType, texture, supportsMips );
 
@@ -900,6 +902,8 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 			}
 
+			cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );
+
 		}
 
 		const image = cubeImage[ 0 ],
@@ -1631,6 +1635,66 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 	}
 
+	function verifyColorSpace( texture, image ) {
+
+		const encoding = texture.encoding;
+		const format = texture.format;
+		const type = texture.type;
+
+		if ( texture.isCompressedTexture === true || texture.format === _SRGBFormat || texture.format === _SRGBAFormat ) return image;
+
+		if ( encoding !== LinearEncoding ) {
+
+			// sRGB
+
+			if ( encoding === sRGBEncoding && texture.isVideoTexture !== true ) {
+
+				if ( isWebGL2 === false ) {
+
+					// in WebGL 1, try to use EXT_sRGB extension and unsized formats
+
+					if ( extensions.has( 'EXT_sRGB' ) === true && ( format === RGBFormat || format === RGBAFormat ) ) {
+
+						if ( format === RGBFormat ) texture.format = _SRGBFormat;
+						if ( format === RGBAFormat ) texture.format = _SRGBAFormat;
+
+						// it's not possible to generate mips in WebGL 1 with the above formats
+
+						texture.minFilter = LinearFilter;
+						texture.generateMipmaps = false;
+
+					} else {
+
+						// slow fallback (CPU decode)
+
+						image = ImageUtils.sRGBToLinear( image );
+
+					}
+
+				} else {
+
+					// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
+
+					if ( format !== RGBAFormat || type !== UnsignedByteType ) {
+
+						console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );
+
+					}
+
+				}
+
+			} else {
+
+				console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding );
+
+			}
+
+		}
+
+		return image;
+
+	}
+
 	// backwards compatibility
 
 	let warnedTexture2D = false;

+ 20 - 1
src/renderers/webgl/WebGLUtils.js

@@ -1,4 +1,4 @@
-import { RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBAFormat, RGBFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, sRGBEncoding } from '../../constants.js';
+import { RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBAFormat, RGBFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, sRGBEncoding, _SRGBFormat, _SRGBAFormat } from '../../constants.js';
 
 function WebGLUtils( gl, extensions, capabilities ) {
 
@@ -47,6 +47,25 @@ function WebGLUtils( gl, extensions, capabilities ) {
 		if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
 		if ( p === RedFormat ) return gl.RED;
 
+		// WebGL 1 sRGB fallback
+
+		if ( p === _SRGBFormat || p === _SRGBAFormat ) {
+
+			extension = extensions.get( 'EXT_sRGB' );
+
+			if ( extension !== null ) {
+
+				if ( p === _SRGBFormat ) return extension.SRGB_EXT;
+				if ( p === _SRGBAFormat ) return extension.SRGB_ALPHA_EXT;
+
+			} else {
+
+				return null;
+
+			}
+
+		}
+
 		// WebGL2 formats.
 
 		if ( p === RedIntegerFormat ) return gl.RED_INTEGER;