Explorar o código

WebGLRenderer: Make use of SRGB8_ALPHA8. (#22551)

* WebGLRenderer: Make use of SRGB8_ALPHA8.

* Update screenshots.

* Updated builds.

* Revert "Update screenshots."

This reverts commit 9f7c6cb8ad2ba28515bd8ce909b661f14a59cf31.

* Update screenshots.

* Examples: Let SSRPass and SSRrPass work in linear space.

* Examples: Clean up.

* PMREMGenerator: Avoid inline decode/encode when using SRGB8_ALPHA8.

* Updated builds.

* Update screenshots.

* Revert "Updated builds."

This reverts commit 0fd81f8a8452323c0b21a880f6781e3456bf5fdb.

* Revert "Updated builds."

This reverts commit 447e88a55c47fd9163360c6be957b784d098f352.
Michael Herzog %!s(int64=3) %!d(string=hai) anos
pai
achega
cba9457c1c

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

@@ -2761,11 +2761,6 @@ class GLTFParser {
 
 		let sourceURI = source.uri || '';
 		let isObjectURL = false;
-		let hasAlpha = true;
-
-		const isJPEG = sourceURI.search( /\.jpe?g($|\?)/i ) > 0 || sourceURI.search( /^data\:image\/jpeg/ ) === 0;
-
-		if ( source.mimeType === 'image/jpeg' || isJPEG ) hasAlpha = false;
 
 		if ( source.bufferView !== undefined ) {
 
@@ -2773,19 +2768,6 @@ class GLTFParser {
 
 			sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
 
-				if ( source.mimeType === 'image/png' ) {
-
-					// Inspect the PNG 'IHDR' chunk to determine whether the image could have an
-					// alpha channel. This check is conservative — the image could have an alpha
-					// channel with all values == 1, and the indexed type (colorType == 3) only
-					// sometimes contains alpha.
-					//
-					// https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
-					const colorType = new DataView( bufferView, 25, 1 ).getUint8( 0, false );
-					hasAlpha = colorType === 6 || colorType === 4 || colorType === 3;
-
-				}
-
 				isObjectURL = true;
 				const blob = new Blob( [ bufferView ], { type: source.mimeType } );
 				sourceURI = URL.createObjectURL( blob );
@@ -2836,9 +2818,6 @@ class GLTFParser {
 
 			if ( textureDef.name ) texture.name = textureDef.name;
 
-			// When there is definitely no alpha channel in the texture, set RGBFormat to save space.
-			if ( ! hasAlpha ) texture.format = RGBFormat;
-
 			const samplers = json.samplers || {};
 			const sampler = samplers[ textureDef.sampler ] || {};
 

+ 1 - 4
examples/jsm/postprocessing/SSRPass.js

@@ -24,7 +24,7 @@ import { CopyShader } from '../shaders/CopyShader.js';
 
 class SSRPass extends Pass {
 
-	constructor( { renderer, scene, camera, width, height, selects, encoding, bouncing = false, groundReflector } ) {
+	constructor( { renderer, scene, camera, width, height, selects, bouncing = false, groundReflector } ) {
 
 		super();
 
@@ -44,8 +44,6 @@ class SSRPass extends Pass {
 		this.maxDistance = SSRShader.uniforms.maxDistance.value;
 		this.thickness = SSRShader.uniforms.thickness.value;
 
-		this.encoding = encoding;
-
 		this.tempColor = new Color();
 
 		this._selects = selects;
@@ -359,7 +357,6 @@ class SSRPass extends Pass {
 
 		// render beauty and depth
 
-		if ( this.encoding ) this.beautyRenderTarget.texture.encoding = this.encoding;
 		renderer.setRenderTarget( this.beautyRenderTarget );
 		renderer.clear();
 		if ( this.groundReflector ) {

+ 1 - 4
examples/jsm/postprocessing/SSRrPass.js

@@ -24,7 +24,7 @@ import { CopyShader } from '../shaders/CopyShader.js';
 
 class SSRrPass extends Pass {
 
-	constructor( { renderer, scene, camera, width, height, selects, encoding } ) {
+	constructor( { renderer, scene, camera, width, height, selects } ) {
 
 		super();
 
@@ -44,8 +44,6 @@ class SSRrPass extends Pass {
 		this.maxDistance = SSRrShader.uniforms.maxDistance.value;
 		this.surfDist = SSRrShader.uniforms.surfDist.value;
 
-		this.encoding = encoding;
-
 		this.tempColor = new Color();
 
 		this.selects = selects;
@@ -274,7 +272,6 @@ class SSRrPass extends Pass {
 
 		// render beauty and depth
 
-		if ( this.encoding ) this.beautyRenderTarget.texture.encoding = this.encoding;
 		renderer.setRenderTarget( this.beautyRenderTarget );
 		renderer.clear();
 		this.scene.children.forEach( child => {

BIN=BIN
examples/screenshots/webgl_lightprobe.jpg


BIN=BIN
examples/screenshots/webgl_loader_md2.jpg


BIN=BIN
examples/screenshots/webgl_materials_displacementmap.jpg


BIN=BIN
examples/screenshots/webgl_postprocessing_ssr.jpg


BIN=BIN
examples/screenshots/webgl_postprocessing_ssrr.jpg


+ 3 - 2
examples/webgl_postprocessing_ssr.html

@@ -27,6 +27,8 @@
 		import { GUI } from './jsm/libs/dat.gui.module.js';
 		import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
 		import { SSRPass } from './jsm/postprocessing/SSRPass.js';
+		import { ShaderPass } from './jsm/postprocessing/ShaderPass.js';
+		import { GammaCorrectionShader } from './jsm/shaders/GammaCorrectionShader.js';
 		import { ReflectorForSSRPass } from './jsm/objects/ReflectorForSSRPass.js';
 
 		import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
@@ -144,7 +146,6 @@
 			// renderer
 			renderer = new THREE.WebGLRenderer( { antialias: false } );
 			renderer.setSize( window.innerWidth, window.innerHeight );
-			renderer.outputEncoding = THREE.sRGBEncoding;
 			container.appendChild( renderer.domElement );
 
 			//
@@ -171,12 +172,12 @@
 				camera,
 				width: innerWidth,
 				height: innerHeight,
-				encoding: THREE.sRGBEncoding,
 				groundReflector: params.groundReflector ? groundReflector : null,
 				selects: params.groundReflector ? selects : null
 			} );
 
 			composer.addPass( ssrPass );
+			composer.addPass( new ShaderPass( GammaCorrectionShader ) );
 
 			// GUI
 

+ 3 - 2
examples/webgl_postprocessing_ssrr.html

@@ -28,6 +28,8 @@
 		import { GUI } from './jsm/libs/dat.gui.module.js';
 		import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
 		import { SSRrPass } from './jsm/postprocessing/SSRrPass.js';
+		import { ShaderPass } from './jsm/postprocessing/ShaderPass.js';
+		import { GammaCorrectionShader } from './jsm/shaders/GammaCorrectionShader.js';
 
 		import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
 
@@ -147,7 +149,6 @@
 			// renderer
 			renderer = new THREE.WebGLRenderer( { antialias: false } );
 			renderer.setSize( window.innerWidth, window.innerHeight );
-			renderer.outputEncoding = THREE.sRGBEncoding;
 			renderer.autoClear = false;
 			container.appendChild( renderer.domElement );
 
@@ -177,11 +178,11 @@
 				camera,
 				width: innerWidth,
 				height: innerHeight,
-				encoding: THREE.sRGBEncoding,
 				selects: selects
 			} );
 
 			composer.addPass( ssrrPass );
+			composer.addPass( new ShaderPass( GammaCorrectionShader ) );
 
 			// GUI
 

+ 20 - 4
src/extras/PMREMGenerator.js

@@ -8,6 +8,7 @@ import {
 	RGBDEncoding,
 	RGBEEncoding,
 	RGBEFormat,
+	RGBAFormat,
 	RGBM16Encoding,
 	RGBM7Encoding,
 	UnsignedByteType,
@@ -345,6 +346,20 @@ 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;
@@ -380,8 +395,8 @@ class PMREMGenerator {
 
 		}
 
-		uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ];
-		uniforms[ 'outputEncoding' ].value = ENCODINGS[ cubeUVRenderTarget.texture.encoding ];
+		this._setEncoding( uniforms[ 'inputEncoding' ], texture );
+		this._setEncoding( uniforms[ 'outputEncoding' ], cubeUVRenderTarget.texture );
 
 		_setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
 
@@ -512,8 +527,9 @@ class PMREMGenerator {
 
 		blurUniforms[ 'dTheta' ].value = radiansPerPixel;
 		blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
-		blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
-		blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
+
+		this._setEncoding( blurUniforms[ 'inputEncoding' ], targetIn.texture );
+		this._setEncoding( blurUniforms[ 'outputEncoding' ], targetIn.texture );
 
 		const outputSize = _sizeLods[ lodOut ];
 		const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );

+ 0 - 6
src/loaders/TextureLoader.js

@@ -1,4 +1,3 @@
-import { RGBAFormat, RGBFormat } from '../constants.js';
 import { ImageLoader } from './ImageLoader.js';
 import { Texture } from '../textures/Texture.js';
 import { Loader } from './Loader.js';
@@ -22,11 +21,6 @@ class TextureLoader extends Loader {
 		loader.load( url, function ( image ) {
 
 			texture.image = image;
-
-			// JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
-			const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
-
-			texture.format = isJPEG ? RGBFormat : RGBAFormat;
 			texture.needsUpdate = true;
 
 			if ( onLoad !== undefined ) {

+ 7 - 1
src/renderers/webgl/WebGLPrograms.js

@@ -1,4 +1,4 @@
-import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, LinearEncoding, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping } from '../../constants.js';
+import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, LinearEncoding, sRGBEncoding, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, RGBAFormat, UnsignedByteType } from '../../constants.js';
 import { WebGLProgram } from './WebGLProgram.js';
 import { ShaderLib } from '../shaders/ShaderLib.js';
 import { UniformsUtils } from '../shaders/UniformsUtils.js';
@@ -106,6 +106,12 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 		}
 
+		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
+
+		}
+
 		return encoding;
 
 	}

+ 8 - 8
src/renderers/webgl/WebGLTextures.js

@@ -1,4 +1,4 @@
-import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping } from '../../constants.js';
+import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, sRGBEncoding } from '../../constants.js';
 import * as MathUtils from '../../math/MathUtils.js';
 import { createElementNS } from '../../utils.js';
 
@@ -132,7 +132,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 	}
 
-	function getInternalFormat( internalFormatName, glFormat, glType ) {
+	function getInternalFormat( internalFormatName, glFormat, glType, encoding ) {
 
 		if ( isWebGL2 === false ) return glFormat;
 
@@ -166,7 +166,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 = _gl.RGBA8;
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( encoding === sRGBEncoding ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
 
 		}
 
@@ -532,7 +532,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 			glFormat = utils.convert( texture.format );
 
 		let glType = utils.convert( texture.type ),
-			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
+			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 
 		setTextureParameters( textureType, texture, supportsMips );
 
@@ -758,7 +758,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 			supportsMips = isPowerOfTwo( image ) || isWebGL2,
 			glFormat = utils.convert( texture.format ),
 			glType = utils.convert( texture.type ),
-			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
+			glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 
 		setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
 
@@ -857,7 +857,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 		const glFormat = utils.convert( texture.format );
 		const glType = utils.convert( texture.type );
-		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
+		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 
 		if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
 
@@ -938,7 +938,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 			const glFormat = utils.convert( texture.format );
 			const glType = utils.convert( texture.type );
-			const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
+			const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 
 			if ( isMultisample ) {
 
@@ -1131,7 +1131,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 					const glFormat = utils.convert( texture.format );
 					const glType = utils.convert( texture.type );
-					const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
+					const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
 					const samples = getRenderTargetSamples( renderTarget );
 					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
 

+ 1 - 2
src/textures/CubeTexture.js

@@ -1,5 +1,5 @@
 import { Texture } from './Texture.js';
-import { CubeReflectionMapping, RGBFormat } from '../constants.js';
+import { CubeReflectionMapping } from '../constants.js';
 
 class CubeTexture extends Texture {
 
@@ -7,7 +7,6 @@ class CubeTexture extends Texture {
 
 		images = images !== undefined ? images : [];
 		mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
-		format = format !== undefined ? format : RGBFormat;
 
 		super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
 

+ 2 - 1
utils/build/rollup.config.js

@@ -158,7 +158,8 @@ export function glconstants() {
 		MAX_SAMPLES: 36183,
 		READ_FRAMEBUFFER: 36008,
 		DRAW_FRAMEBUFFER: 36009,
-		SAMPLE_ALPHA_TO_COVERAGE: 32926
+		SAMPLE_ALPHA_TO_COVERAGE: 32926,
+		SRGB8_ALPHA8: 35907
 	};
 
 	return {