diff --git a/src/extras/PMREMGenerator.js b/src/extras/PMREMGenerator.js index 12a4ee005acf4a..86e3d54e1d8233 100644 --- a/src/extras/PMREMGenerator.js +++ b/src/extras/PMREMGenerator.js @@ -3,14 +3,14 @@ import { CubeRefractionMapping, CubeUVReflectionMapping, LinearEncoding, - LinearFilter, NoToneMapping, + NearestFilter, NoBlending, RGBEEncoding, RGBAFormat, + RGBEFormat, UnsignedByteType, - sRGBEncoding, - HalfFloatType + sRGBEncoding } from '../constants.js'; import { BufferAttribute } from '../core/BufferAttribute.js'; @@ -226,12 +226,12 @@ class PMREMGenerator { _allocateTargets( texture ) { // warning: null texture is valid const params = { - magFilter: LinearFilter, - minFilter: LinearFilter, + magFilter: NearestFilter, + minFilter: NearestFilter, generateMipmaps: false, - type: HalfFloatType, - format: RGBAFormat, - encoding: LinearEncoding, + type: UnsignedByteType, + format: RGBEFormat, + encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding, depthBuffer: false }; @@ -259,10 +259,12 @@ class PMREMGenerator { const renderer = this._renderer; const originalAutoClear = renderer.autoClear; + const outputEncoding = renderer.outputEncoding; const toneMapping = renderer.toneMapping; renderer.getClearColor( _clearColor ); renderer.toneMapping = NoToneMapping; + renderer.outputEncoding = LinearEncoding; renderer.autoClear = false; const backgroundMaterial = new MeshBasicMaterial( { @@ -332,6 +334,7 @@ class PMREMGenerator { backgroundBox.material.dispose(); renderer.toneMapping = toneMapping; + renderer.outputEncoding = outputEncoding; renderer.autoClear = originalAutoClear; scene.background = background; @@ -389,6 +392,7 @@ class PMREMGenerator { } this._setEncoding( uniforms[ 'inputEncoding' ], texture ); + this._setEncoding( uniforms[ 'outputEncoding' ], cubeUVRenderTarget.texture ); _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX ); @@ -520,6 +524,9 @@ class PMREMGenerator { blurUniforms[ 'dTheta' ].value = radiansPerPixel; blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn; + 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 ); const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 ); @@ -532,6 +539,14 @@ class PMREMGenerator { } +function _isLDR( texture ) { + + if ( texture === undefined || texture.type !== UnsignedByteType ) return false; + + return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding; + +} + function _createPlanes() { const _lodPlanes = []; @@ -644,7 +659,9 @@ function _getBlurShader( maxSamples ) { 'latitudinal': { value: false }, 'dTheta': { value: 0 }, 'mipInt': { value: 0 }, - 'poleAxis': { value: poleAxis } + 'poleAxis': { value: poleAxis }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } }, vertexShader: _getCommonVertexShader(), @@ -710,6 +727,8 @@ function _getBlurShader( maxSamples ) { } + gl_FragColor = linearToOutputTexel( gl_FragColor ); + } `, @@ -733,7 +752,8 @@ function _getEquirectShader() { uniforms: { 'envMap': { value: null }, 'texelSize': { value: texelSize }, - 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] } + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } }, vertexShader: _getCommonVertexShader(), @@ -773,6 +793,8 @@ function _getEquirectShader() { vec3 bm = mix( bl, br, f.x ); gl_FragColor.rgb = mix( tm, bm, f.y ); + gl_FragColor = linearToOutputTexel( gl_FragColor ); + } `, @@ -794,7 +816,8 @@ function _getCubemapShader() { uniforms: { 'envMap': { value: null }, - 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] } + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } }, vertexShader: _getCommonVertexShader(), @@ -812,7 +835,9 @@ function _getCubemapShader() { void main() { - gl_FragColor = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ); + gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb; + gl_FragColor = linearToOutputTexel( gl_FragColor ); } `, @@ -895,6 +920,7 @@ function _getEncodings() { return /* glsl */` uniform int inputEncoding; + uniform int outputEncoding; #include @@ -916,6 +942,40 @@ function _getEncodings() { } + vec4 linearToOutputTexel( vec4 value ) { + + if ( outputEncoding == 0 ) { + + return value; + + } else if ( outputEncoding == 1 ) { + + return LinearTosRGB( value ); + + } else if ( outputEncoding == 2 ) { + + return LinearToRGBE( value ); + + } else if ( outputEncoding == 3 ) { + + return LinearToRGBM( value, 7.0 ); + + } else if ( outputEncoding == 4 ) { + + return LinearToRGBM( value, 16.0 ); + + } else if ( outputEncoding == 5 ) { + + return LinearToRGBD( value, 256.0 ); + + } else { + + return LinearToGamma( value, 2.2 ); + + } + + } + vec4 envMapTexelToLinear( vec4 color ) { return inputTexelToLinear( color ); diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index b5e08ca3f6811a..eb4961bb17d780 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1410,7 +1410,6 @@ function WebGLRenderer( parameters = {} ) { materialProperties.numIntersection = parameters.numClipIntersection; materialProperties.vertexAlphas = parameters.vertexAlphas; materialProperties.vertexTangents = parameters.vertexTangents; - materialProperties.toneMapping = parameters.toneMapping; } @@ -1429,7 +1428,6 @@ function WebGLRenderer( parameters = {} ) { const morphTargets = !! geometry.morphAttributes.position; const morphNormals = !! geometry.morphAttributes.normal; const morphTargetsCount = !! geometry.morphAttributes.position ? geometry.morphAttributes.position.length : 0; - const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; const materialProperties = properties.get( material ); const lights = currentRenderState.state.lights; @@ -1511,10 +1509,6 @@ function WebGLRenderer( parameters = {} ) { needsProgramChange = true; - } else if ( materialProperties.toneMapping !== toneMapping ) { - - needsProgramChange = true; - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { needsProgramChange = true; diff --git a/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js index 5e5288c83b1485..859cb8126ae122 100644 --- a/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js @@ -89,7 +89,11 @@ export default /* glsl */` float texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize ); - vec2 uv = getUV( direction, face ) * ( faceSize - 1.0 ) + 0.5; + vec2 uv = getUV( direction, face ) * ( faceSize - 1.0 ); + + vec2 f = fract( uv ); + + uv += 0.5 - f; if ( face > 2.0 ) { @@ -113,7 +117,25 @@ export default /* glsl */` uv *= texelSize; - return texture2D( envMap, uv ).rgb; + vec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb; + + uv.x += texelSize; + + vec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb; + + uv.y += texelSize; + + vec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb; + + uv.x -= texelSize; + + vec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb; + + vec3 tm = mix( tl, tr, f.x ); + + vec3 bm = mix( bl, br, f.x ); + + return mix( tm, bm, f.y ); }