Skip to content

Commit e0d980b

Browse files
committed
Revert "WebGLRenderer: Remove inline sRGB decode. (mrdoob#23129)"
This reverts commit 05fc79c.
1 parent c0160a3 commit e0d980b

25 files changed

+214
-210
lines changed

examples/jsm/loaders/GLTFLoader.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,7 @@ class GLTFMeshStandardSGMaterial extends MeshStandardMaterial {
14771477
'vec3 specularFactor = specular;',
14781478
'#ifdef USE_SPECULARMAP',
14791479
' vec4 texelSpecular = texture2D( specularMap, vUv );',
1480+
' texelSpecular = sRGBToLinear( texelSpecular );',
14801481
' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
14811482
' specularFactor *= texelSpecular.rgb;',
14821483
'#endif'

examples/jsm/nodes/utils/ColorSpaceNode.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,9 @@ class ColorSpaceNode extends TempNode {
5757

5858
}
5959

60-
fromDecoding() {
60+
fromDecoding( encoding ) {
6161

62-
// TODO: Remove fromDecoding()
63-
64-
const components = ColorSpaceNode.getEncodingComponents( LinearEncoding );
62+
const components = ColorSpaceNode.getEncodingComponents( encoding );
6563

6664
this.method = components[ 0 ] + 'ToLinear';
6765
this.factor = components[ 1 ];
@@ -108,6 +106,14 @@ ColorSpaceNode.Nodes = ( function () {
108106
}`
109107
);
110108

109+
const sRGBToLinear = new FunctionNode( /* glsl */`
110+
vec4 sRGBToLinear( in vec4 value ) {
111+
112+
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 );
113+
114+
}`
115+
);
116+
111117
const LinearTosRGB = new FunctionNode( /* glsl */`
112118
vec4 LinearTosRGB( in vec4 value ) {
113119
@@ -118,12 +124,15 @@ ColorSpaceNode.Nodes = ( function () {
118124

119125
return {
120126
LinearToLinear: LinearToLinear,
127+
sRGBToLinear: sRGBToLinear,
121128
LinearTosRGB: LinearTosRGB
122129
};
123130

124131
} )();
125132

126133
ColorSpaceNode.LINEAR_TO_LINEAR = 'LinearToLinear';
134+
135+
ColorSpaceNode.SRGB_TO_LINEAR = 'sRGBToLinear';
127136
ColorSpaceNode.LINEAR_TO_SRGB = 'LinearTosRGB';
128137

129138
ColorSpaceNode.getEncodingComponents = function ( encoding ) {

examples/jsm/renderers/nodes/display/ColorSpaceNode.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import TempNode from '../core/Node.js';
22
import { ShaderNode,
33
vec3,
4-
pow, mul, sub, mix, join,
4+
pow, mul, add, sub, mix, join,
55
lessThanEqual } from '../ShaderNode.js';
66

77
import { LinearEncoding, sRGBEncoding } from 'three';
@@ -12,6 +12,22 @@ export const LinearToLinear = new ShaderNode( ( inputs ) => {
1212

1313
} );
1414

15+
export const sRGBToLinear = new ShaderNode( ( inputs ) => {
16+
17+
const { value } = inputs;
18+
19+
const rgb = value.rgb;
20+
21+
const a = pow( add( mul( rgb, 0.9478672986 ), vec3( 0.0521327014 ) ), vec3( 2.4 ) );
22+
const b = mul( rgb, 0.0773993808 );
23+
const factor = vec3( lessThanEqual( rgb, vec3( 0.04045 ) ) );
24+
25+
const rgbResult = mix( a, b, factor );
26+
27+
return join( rgbResult.r, rgbResult.g, rgbResult.b, value.a );
28+
29+
} );
30+
1531
export const LinearTosRGB = new ShaderNode( ( inputs ) => {
1632

1733
const { value } = inputs;
@@ -30,12 +46,15 @@ export const LinearTosRGB = new ShaderNode( ( inputs ) => {
3046

3147
const EncodingLib = {
3248
LinearToLinear,
49+
sRGBToLinear,
3350
LinearTosRGB
3451
};
3552

3653
class ColorSpaceNode extends TempNode {
3754

3855
static LINEAR_TO_LINEAR = 'LinearToLinear';
56+
57+
static SRGB_TO_LINEAR = 'sRGBToLinear';
3958
static LINEAR_TO_SRGB = 'LinearTosRGB';
4059

4160
constructor( method, node ) {

examples/webgl_lightprobe_cubecamera.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@
5454
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
5555
camera.position.set( 0, 0, 30 );
5656

57-
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256 );
57+
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, {
58+
encoding: THREE.sRGBEncoding, // since gamma is applied during rendering, the cubeCamera renderTarget texture encoding must be sRGBEncoding
59+
format: THREE.RGBAFormat
60+
} );
5861

5962
cubeCamera = new THREE.CubeCamera( 1, 1000, cubeRenderTarget );
6063

examples/webgl_materials_nodes.html

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@
5252
const library = {};
5353
let serialized = false;
5454
const textures = {
55-
brick: { url: 'textures/brick_diffuse.jpg', encoding: THREE.sRGBEncoding },
56-
grass: { url: 'textures/terrain/grasslight-big.jpg', encoding: THREE.sRGBEncoding },
57-
grassNormal: { url: 'textures/terrain/grasslight-big-nm.jpg', encoding: THREE.LinearEncoding },
58-
decalDiffuse: { url: 'textures/decal/decal-diffuse.png', encoding: THREE.sRGBEncoding },
59-
decalNormal: { url: 'textures/decal/decal-normal.jpg', encoding: THREE.LinearEncoding },
60-
cloud: { url: 'textures/lava/cloud.png', encoding: THREE.sRGBEncoding },
61-
spherical: { url: 'textures/envmap.png', encoding: THREE.sRGBEncoding }
55+
brick: { url: 'textures/brick_diffuse.jpg' },
56+
grass: { url: 'textures/terrain/grasslight-big.jpg' },
57+
grassNormal: { url: 'textures/terrain/grasslight-big-nm.jpg' },
58+
decalDiffuse: { url: 'textures/decal/decal-diffuse.png' },
59+
decalNormal: { url: 'textures/decal/decal-normal.jpg' },
60+
cloud: { url: 'textures/lava/cloud.png' },
61+
spherical: { url: 'textures/envmap.png' }
6262
};
6363

6464
const param = { example: new URL( window.location.href ).searchParams.get( 'e' ) || 'mesh-standard' };
@@ -71,7 +71,6 @@
7171

7272
texture = textures[ name ].texture = new THREE.TextureLoader().load( textures[ name ].url );
7373
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
74-
texture.encoding = textures[ name ].encoding;
7574

7675
library[ texture.uuid ] = texture;
7776

@@ -200,7 +199,7 @@
200199
'basic / spherical-reflection': 'spherical-reflection',
201200
'basic / standard': 'standard',
202201
'basic / uv-transform': 'uv-transform',
203-
202+
204203
'adv / bias': 'bias',
205204
'adv / camera-depth': 'camera-depth',
206205
'adv / caustic': 'caustic',
@@ -228,7 +227,7 @@
228227
'node / normal': 'node-normal',
229228
'node / position': 'node-position',
230229
'node / reflect': 'node-reflect',
231-
230+
232231
'misc / basic-material': 'basic-material',
233232
'misc / custom-attribute': 'custom-attribute',
234233
'misc / firefly': 'firefly',

src/constants.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,3 @@ export const StreamCopyUsage = 35042;
175175

176176
export const GLSL1 = '100';
177177
export const GLSL3 = '300 es';
178-
179-
export const _SRGBAFormat = 1035; // fallback for WebGL 1

src/extras/ImageUtils.js

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { createElementNS } from '../utils.js';
2-
import { SRGBToLinear } from '../math/Color.js';
32

43
let _canvas;
54

@@ -62,68 +61,6 @@ class ImageUtils {
6261

6362
}
6463

65-
static sRGBToLinear( image ) {
66-
67-
if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
68-
( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
69-
( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
70-
71-
const canvas = createElementNS( 'canvas' );
72-
73-
canvas.width = image.width;
74-
canvas.height = image.height;
75-
76-
const context = canvas.getContext( '2d' );
77-
context.drawImage( image, 0, 0, image.width, image.height );
78-
79-
const imageData = context.getImageData( 0, 0, image.width, image.height );
80-
const data = imageData.data;
81-
82-
for ( let i = 0; i < data.length; i ++ ) {
83-
84-
data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
85-
86-
}
87-
88-
context.putImageData( imageData, 0, 0 );
89-
90-
return canvas;
91-
92-
} else if ( image.data ) {
93-
94-
const data = image.data.slice( 0 );
95-
96-
for ( let i = 0; i < data.length; i ++ ) {
97-
98-
if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {
99-
100-
data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
101-
102-
} else {
103-
104-
// assuming float
105-
106-
data[ i ] = SRGBToLinear( data[ i ] );
107-
108-
}
109-
110-
}
111-
112-
return {
113-
data: data,
114-
width: image.width,
115-
height: image.height
116-
};
117-
118-
} else {
119-
120-
console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
121-
return image;
122-
123-
}
124-
125-
}
126-
12764
}
12865

12966
export { ImageUtils };

src/extras/PMREMGenerator.js

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
NoToneMapping,
88
NoBlending,
99
RGBAFormat,
10+
UnsignedByteType,
11+
sRGBEncoding,
1012
HalfFloatType
1113
} from '../constants.js';
1214

@@ -40,6 +42,11 @@ const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
4042
// samples and exit early, but not recompile the shader.
4143
const MAX_SAMPLES = 20;
4244

45+
const ENCODINGS = {
46+
[ LinearEncoding ]: 0,
47+
[ sRGBEncoding ]: 1
48+
};
49+
4350
const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
4451
const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
4552
const _clearColor = /*@__PURE__*/ new Color();
@@ -335,6 +342,20 @@ class PMREMGenerator {
335342

336343
}
337344

345+
_setEncoding( uniform, texture ) {
346+
347+
if ( this._renderer.capabilities.isWebGL2 === true && texture.format === RGBAFormat && texture.type === UnsignedByteType && texture.encoding === sRGBEncoding ) {
348+
349+
uniform.value = ENCODINGS[ LinearEncoding ];
350+
351+
} else {
352+
353+
uniform.value = ENCODINGS[ texture.encoding ];
354+
355+
}
356+
357+
}
358+
338359
_textureToCubeUV( texture, cubeUVRenderTarget ) {
339360

340361
const renderer = this._renderer;
@@ -374,6 +395,8 @@ class PMREMGenerator {
374395

375396
}
376397

398+
this._setEncoding( uniforms[ 'inputEncoding' ], texture );
399+
377400
_setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
378401

379402
renderer.setRenderTarget( cubeUVRenderTarget );
@@ -648,6 +671,8 @@ function _getBlurShader( maxSamples ) {
648671
uniform float mipInt;
649672
uniform vec3 poleAxis;
650673
674+
${ _getEncodings() }
675+
651676
#define ENVMAP_TYPE_CUBE_UV
652677
#include <cube_uv_reflection_fragment>
653678
@@ -714,7 +739,8 @@ function _getEquirectShader() {
714739

715740
uniforms: {
716741
'envMap': { value: null },
717-
'texelSize': { value: texelSize }
742+
'texelSize': { value: texelSize },
743+
'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }
718744
},
719745

720746
vertexShader: _getCommonVertexShader(),
@@ -729,6 +755,8 @@ function _getEquirectShader() {
729755
uniform sampler2D envMap;
730756
uniform vec2 texelSize;
731757
758+
${ _getEncodings() }
759+
732760
#include <common>
733761
734762
void main() {
@@ -740,13 +768,13 @@ function _getEquirectShader() {
740768
741769
vec2 f = fract( uv / texelSize - 0.5 );
742770
uv -= f * texelSize;
743-
vec3 tl = texture2D ( envMap, uv ).rgb;
771+
vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
744772
uv.x += texelSize.x;
745-
vec3 tr = texture2D ( envMap, uv ).rgb;
773+
vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
746774
uv.y += texelSize.y;
747-
vec3 br = texture2D ( envMap, uv ).rgb;
775+
vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
748776
uv.x -= texelSize.x;
749-
vec3 bl = texture2D ( envMap, uv ).rgb;
777+
vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
750778
751779
vec3 tm = mix( tl, tr, f.x );
752780
vec3 bm = mix( bl, br, f.x );
@@ -773,7 +801,8 @@ function _getCubemapShader() {
773801

774802
uniforms: {
775803
'envMap': { value: null },
776-
'flipEnvMap': { value: - 1 }
804+
'flipEnvMap': { value: - 1 },
805+
'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }
777806
},
778807

779808
vertexShader: _getCommonVertexShader(),
@@ -789,9 +818,11 @@ function _getCubemapShader() {
789818
790819
uniform samplerCube envMap;
791820
821+
${ _getEncodings() }
822+
792823
void main() {
793824
794-
gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );
825+
gl_FragColor = envMapTexelToLinear( textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ) );
795826
796827
}
797828
`,
@@ -869,4 +900,35 @@ function _getCommonVertexShader() {
869900

870901
}
871902

903+
function _getEncodings() {
904+
905+
return /* glsl */`
906+
907+
uniform int inputEncoding;
908+
909+
#include <encodings_pars_fragment>
910+
911+
vec4 inputTexelToLinear( vec4 value ) {
912+
913+
if ( inputEncoding == 0 ) {
914+
915+
return value;
916+
917+
} else {
918+
919+
return sRGBToLinear( value );
920+
921+
}
922+
923+
}
924+
925+
vec4 envMapTexelToLinear( vec4 color ) {
926+
927+
return inputTexelToLinear( color );
928+
929+
}
930+
`;
931+
932+
}
933+
872934
export { PMREMGenerator };

0 commit comments

Comments
 (0)