diff --git a/examples/js/pmrem/PMREMCubeUVPacker.js b/examples/js/pmrem/PMREMCubeUVPacker.js deleted file mode 100644 index 1fe2523fa032d70b6027894187fb810253ad9321..0000000000000000000000000000000000000000 --- a/examples/js/pmrem/PMREMCubeUVPacker.js +++ /dev/null @@ -1,233 +0,0 @@ -/** - * @author Prashant Sharma / spidersharma03 - * @author Ben Houston / bhouston, https://clara.io - * - * This class takes the cube lods(corresponding to different roughness values), and creates a single cubeUV - * Texture. The format for a given roughness set of faces is simply:: - * +X+Y+Z - * -X-Y-Z - * For every roughness a mip map chain is also saved, which is essential to remove the texture artifacts due to - * minification. - * Right now for every face a PlaneMesh is drawn, which leads to a lot of geometry draw calls, but can be replaced - * later by drawing a single buffer and by sending the appropriate faceIndex via vertex attributes. - * The arrangement of the faces is fixed, as assuming this arrangement, the sampling function has been written. - */ - -THREE.PMREMCubeUVPacker = ( function () { - - var camera = new THREE.OrthographicCamera(); - var scene = new THREE.Scene(); - var shader = getShader(); - - var PMREMCubeUVPacker = function ( cubeTextureLods ) { - - this.cubeLods = cubeTextureLods; - var size = cubeTextureLods[ 0 ].width * 4; - - var sourceTexture = cubeTextureLods[ 0 ].texture; - var params = { - format: sourceTexture.format, - magFilter: sourceTexture.magFilter, - minFilter: sourceTexture.minFilter, - type: sourceTexture.type, - generateMipmaps: sourceTexture.generateMipmaps, - anisotropy: sourceTexture.anisotropy, - encoding: ( sourceTexture.encoding === THREE.RGBEEncoding ) ? THREE.RGBM16Encoding : sourceTexture.encoding - }; - - if ( params.encoding === THREE.RGBM16Encoding ) { - - params.magFilter = THREE.LinearFilter; - params.minFilter = THREE.LinearFilter; - - } - - this.CubeUVRenderTarget = new THREE.WebGLRenderTarget( size, size, params ); - this.CubeUVRenderTarget.texture.name = "PMREMCubeUVPacker.cubeUv"; - this.CubeUVRenderTarget.texture.mapping = THREE.CubeUVReflectionMapping; - - this.objects = []; - - var geometry = new THREE.PlaneBufferGeometry( 1, 1 ); - - var faceOffsets = []; - faceOffsets.push( new THREE.Vector2( 0, 0 ) ); - faceOffsets.push( new THREE.Vector2( 1, 0 ) ); - faceOffsets.push( new THREE.Vector2( 2, 0 ) ); - faceOffsets.push( new THREE.Vector2( 0, 1 ) ); - faceOffsets.push( new THREE.Vector2( 1, 1 ) ); - faceOffsets.push( new THREE.Vector2( 2, 1 ) ); - - var textureResolution = size; - size = cubeTextureLods[ 0 ].width; - - var offset2 = 0; - var c = 4.0; - this.numLods = Math.log( cubeTextureLods[ 0 ].width ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 - for ( var i = 0; i < this.numLods; i ++ ) { - - var offset1 = ( textureResolution - textureResolution / c ) * 0.5; - if ( size > 16 ) c *= 2; - var nMips = size > 16 ? 6 : 1; - var mipOffsetX = 0; - var mipOffsetY = 0; - var mipSize = size; - - for ( var j = 0; j < nMips; j ++ ) { - - // Mip Maps - for ( var k = 0; k < 6; k ++ ) { - - // 6 Cube Faces - var material = shader.clone(); - material.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; - material.envMap = this.cubeLods[ i ].texture; - material.uniforms[ 'faceIndex' ].value = k; - material.uniforms[ 'mapSize' ].value = mipSize; - - var planeMesh = new THREE.Mesh( geometry, material ); - planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX; - planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY; - planeMesh.material.side = THREE.BackSide; - planeMesh.scale.setScalar( mipSize ); - this.objects.push( planeMesh ); - - } - mipOffsetY += 1.75 * mipSize; - mipOffsetX += 1.25 * mipSize; - mipSize /= 2; - - } - offset2 += 2 * size; - if ( size > 16 ) size /= 2; - - } - - }; - - PMREMCubeUVPacker.prototype = { - - constructor: PMREMCubeUVPacker, - - update: function ( renderer ) { - - var size = this.cubeLods[ 0 ].width * 4; - // top and bottom are swapped for some reason? - camera.left = - size * 0.5; - camera.right = size * 0.5; - camera.top = - size * 0.5; - camera.bottom = size * 0.5; - camera.near = 0; - camera.far = 1; - camera.updateProjectionMatrix(); - - for ( var i = 0; i < this.objects.length; i ++ ) { - - scene.add( this.objects[ i ] ); - - } - - var gammaInput = renderer.gammaInput; - var gammaOutput = renderer.gammaOutput; - var toneMapping = renderer.toneMapping; - var toneMappingExposure = renderer.toneMappingExposure; - var currentRenderTarget = renderer.getRenderTarget(); - - renderer.gammaInput = false; - renderer.gammaOutput = false; - renderer.toneMapping = THREE.LinearToneMapping; - renderer.toneMappingExposure = 1.0; - renderer.setRenderTarget( this.CubeUVRenderTarget ); - renderer.render( scene, camera ); - - renderer.setRenderTarget( currentRenderTarget ); - renderer.toneMapping = toneMapping; - renderer.toneMappingExposure = toneMappingExposure; - renderer.gammaInput = gammaInput; - renderer.gammaOutput = gammaOutput; - - for ( var i = 0; i < this.objects.length; i ++ ) { - - scene.remove( this.objects[ i ] ); - - } - - }, - - dispose: function () { - - for ( var i = 0, l = this.objects.length; i < l; i ++ ) { - - this.objects[ i ].material.dispose(); - - } - - this.objects[ 0 ].geometry.dispose(); - - } - - }; - - function getShader() { - - var shaderMaterial = new THREE.ShaderMaterial( { - - uniforms: { - "faceIndex": { value: 0 }, - "mapSize": { value: 0 }, - "envMap": { value: null }, - "testColor": { value: new THREE.Vector3( 1, 1, 1 ) } - }, - - vertexShader: - "precision highp float;\ - varying vec2 vUv;\ - void main() {\ - vUv = uv;\ - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\ - }", - - fragmentShader: - "precision highp float;\ - varying vec2 vUv;\ - uniform samplerCube envMap;\ - uniform float mapSize;\ - uniform vec3 testColor;\ - uniform int faceIndex;\ - \ - void main() {\ - vec3 sampleDirection;\ - vec2 uv = vUv;\ - uv = uv * 2.0 - 1.0;\ - uv.y *= -1.0;\ - if(faceIndex == 0) {\ - sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\ - } else if(faceIndex == 1) {\ - sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\ - } else if(faceIndex == 2) {\ - sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\ - } else if(faceIndex == 3) {\ - sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\ - } else if(faceIndex == 4) {\ - sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\ - } else {\ - sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\ - }\ - vec4 color = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\ - gl_FragColor = linearToOutputTexel( color );\ - }", - - blending: THREE.NoBlending - - } ); - - shaderMaterial.type = 'PMREMCubeUVPacker'; - - return shaderMaterial; - - } - - - return PMREMCubeUVPacker; - -} )(); diff --git a/examples/js/pmrem/PMREMGenerator.js b/examples/js/pmrem/PMREMGenerator.js index 598d235b81f640e78cada754c4fe955ab89835cc..4e7eb767053c8a99fe766b997b67e274dde3ea07 100644 --- a/examples/js/pmrem/PMREMGenerator.js +++ b/examples/js/pmrem/PMREMGenerator.js @@ -1,293 +1,767 @@ /** - * @author Prashant Sharma / spidersharma03 - * @author Ben Houston / bhouston, https://clara.io + * @author Emmett Lalish / elalish * - * To avoid cube map seams, I create an extra pixel around each face. This way when the cube map is - * sampled by an application later(with a little care by sampling the centre of the texel), the extra 1 border - * of pixels makes sure that there is no seams artifacts present. This works perfectly for cubeUV format as - * well where the 6 faces can be arranged in any manner whatsoever. - * Code in the beginning of fragment shader's main function does this job for a given resolution. - * Run Scene_PMREM_Test.html in the examples directory to see the sampling from the cube lods generated - * by this class. + * This class generates a Prefiltered, Mipmapped Radiance Environment Map + * (PMREM) from a cubeMap environment texture. This allows different levels of + * blur to be quickly accessed based on material roughness. It is packed into a + * special CubeUV format that allows us to perform custom interpolation so that + * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap + * chain, it only goes down to the LOD_MIN level (above), and then creates extra + * even more filtered 'mips' at the same LOD_MIN resolution, associated with + * higher roughness levels. In this way we maintain resolution to smoothly + * interpolate diffuse lighting while limiting sampling computation. */ THREE.PMREMGenerator = ( function () { - var shader = getShader(); - var camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0.0, 1000 ); - var scene = new THREE.Scene(); - var planeMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2, 0 ), shader ); - planeMesh.material.side = THREE.DoubleSide; - scene.add( planeMesh ); - scene.add( camera ); + var LOD_MIN = 4; + var LOD_MAX = 8; + var SIZE_MAX = Math.pow( 2, LOD_MAX ); + // The standard deviations (radians) associated with the extra mips. These are + // chosen to approximate a Trowbridge-Reitz distribution function times the + // geometric shadowing function. These sigma values squared must match the + // variance #defines in cube_uv_reflection_fragment.glsl.js. + var EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + var TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; + // The maximum length of the blur for loop. Smaller sigmas will use fewer + // samples and exit early, but not recompile the shader. + var MAX_SAMPLES = 20; + var ENCODINGS = { + [ THREE.LinearEncoding ]: 0, + [ THREE.sRGBEncoding ]: 1, + [ THREE.RGBEEncoding ]: 2, + [ THREE.RGBM7Encoding ]: 3, + [ THREE.RGBM16Encoding ]: 4, + [ THREE.RGBDEncoding ]: 5, + [ THREE.GammaEncoding ]: 6 + }; + + var _flatCamera = new THREE.OrthographicCamera(); + var _blurMaterial = _getBlurShader( MAX_SAMPLES ); + var _equirectShader = null; + var _cubemapShader = null; + + var { _lodPlanes, _sizeLods, _sigmas } = _createPlanes(); + var _pingPongRenderTarget = null; + var _renderer = null; + + // Golden Ratio + var PHI = ( 1 + Math.sqrt( 5 ) ) / 2; + var INV_PHI = 1 / PHI; + // Vertices of a dodecahedron (except the opposites, which represent the + // same axis), used as axis directions evenly spread on a sphere. + var _axisDirections = [ + new THREE.Vector3( 1, 1, 1 ), + new THREE.Vector3( - 1, 1, 1 ), + new THREE.Vector3( 1, 1, - 1 ), + new THREE.Vector3( - 1, 1, - 1 ), + new THREE.Vector3( 0, PHI, INV_PHI ), + new THREE.Vector3( 0, PHI, - INV_PHI ), + new THREE.Vector3( INV_PHI, 0, PHI ), + new THREE.Vector3( - INV_PHI, 0, PHI ), + new THREE.Vector3( PHI, INV_PHI, 0 ), + new THREE.Vector3( - PHI, INV_PHI, 0 ) ]; + + var PMREMGenerator = function ( renderer ) { + + _renderer = renderer; - var PMREMGenerator = function ( sourceTexture, samplesPerLevel, resolution ) { + }; + + PMREMGenerator.prototype = { + + constructor: PMREMGenerator, + + /** + * Generates a PMREM from a supplied Scene, which can be faster than using an + * image if networking bandwidth is low. Optional sigma specifies a blur radius + * in radians to be applied to the scene before PMREM generation. Optional near + * and far planes ensure the scene is rendered in its entirety (the cubeCamera + * is placed at the origin). + */ + fromScene: function ( scene, sigma = 0, near = 0.1, far = 100 ) { + + var cubeUVRenderTarget = _allocateTargets(); + _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + if ( sigma > 0 ) { + + _blur( cubeUVRenderTarget, 0, 0, sigma ); + + } + _applyPMREM( cubeUVRenderTarget ); + _cleanup(); + + return cubeUVRenderTarget; + + }, + + /** + * Generates a PMREM from an equirectangular texture, which can be either LDR + * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512), + * as this matches best with the 256 x 256 cubemap output. + */ + fromEquirectangular: function ( equirectangular ) { + + equirectangular.magFilter = THREE.NearestFilter; + equirectangular.minFilter = THREE.NearestFilter; + equirectangular.generateMipmaps = false; + + return this.fromCubemap( equirectangular ); + + }, + + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256, + * as this matches best with the 256 x 256 cubemap output. + */ + fromCubemap: function ( cubemap ) { + + var cubeUVRenderTarget = _allocateTargets( cubemap ); + _textureToCubeUV( cubemap, cubeUVRenderTarget ); + _applyPMREM( cubeUVRenderTarget ); + _cleanup(); + + return cubeUVRenderTarget; + + }, + + /** + * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, + * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on + * one of them will cause any others to also become unusable. + */ + dispose: function () { + + _blurMaterial.dispose(); + if ( _cubemapShader != null ) _cubemapShader.dispose(); + if ( _equirectShader != null ) _equirectShader.dispose(); + var plane; + for ( plane of _lodPlanes ) { + + plane.dispose(); + + } + + }, + + }; + + function _createPlanes() { + + var _lodPlanes = []; + var _sizeLods = []; + var _sigmas = []; - this.sourceTexture = sourceTexture; - this.resolution = ( resolution !== undefined ) ? resolution : 256; // NODE: 256 is currently hard coded in the glsl code for performance reasons - this.samplesPerLevel = ( samplesPerLevel !== undefined ) ? samplesPerLevel : 32; + var lod = LOD_MAX; + for ( var i = 0; i < TOTAL_LODS; i ++ ) { - var monotonicEncoding = ( this.sourceTexture.encoding === THREE.LinearEncoding ) || - ( this.sourceTexture.encoding === THREE.GammaEncoding ) || ( this.sourceTexture.encoding === THREE.sRGBEncoding ); + var sizeLod = Math.pow( 2, lod ); + _sizeLods.push( sizeLod ); + var sigma = 1.0 / sizeLod; + if ( i > LOD_MAX - LOD_MIN ) { - this.sourceTexture.minFilter = ( monotonicEncoding ) ? THREE.LinearFilter : THREE.NearestFilter; - this.sourceTexture.magFilter = ( monotonicEncoding ) ? THREE.LinearFilter : THREE.NearestFilter; - this.sourceTexture.generateMipmaps = this.sourceTexture.generateMipmaps && monotonicEncoding; + sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ]; - this.cubeLods = []; + } else if ( i == 0 ) { + + sigma = 0; + + } + _sigmas.push( sigma ); + + var texelSize = 1.0 / ( sizeLod - 1 ); + var min = - texelSize / 2; + var max = 1 + texelSize / 2; + var uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + + var cubeFaces = 6; + var vertices = 6; + var positionSize = 3; + var uvSize = 2; + var faceIndexSize = 1; + + var position = new Float32Array( positionSize * vertices * cubeFaces ); + var uv = new Float32Array( uvSize * vertices * cubeFaces ); + var faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + + for ( var face = 0; face < cubeFaces; face ++ ) { + + var x = ( face % 3 ) * 2 / 3 - 1; + var y = face > 2 ? 0 : - 1; + var coordinates = [ + [ x, y, 0 ], + [ x + 2 / 3, y, 0 ], + [ x + 2 / 3, y + 1, 0 ], + [ x, y, 0 ], + [ x + 2 / 3, y + 1, 0 ], + [ x, y + 1, 0 ] + ]; + position.set( [].concat( ...coordinates ), + positionSize * vertices * face ); + uv.set( uv1, uvSize * vertices * face ); + var fill = [ face, face, face, face, face, face ]; + faceIndex.set( fill, faceIndexSize * vertices * face ); + + } + var planes = new THREE.BufferGeometry(); + planes.setAttribute( + 'position', new THREE.BufferAttribute( position, positionSize ) ); + planes.setAttribute( 'uv', new THREE.BufferAttribute( uv, uvSize ) ); + planes.setAttribute( + 'faceIndex', new THREE.BufferAttribute( faceIndex, faceIndexSize ) ); + _lodPlanes.push( planes ); + + if ( lod > LOD_MIN ) { + + lod --; + + } + + } + return { _lodPlanes, _sizeLods, _sigmas }; + + } + + function _allocateTargets( equirectangular ) { - var size = this.resolution; var params = { - format: this.sourceTexture.format, - magFilter: this.sourceTexture.magFilter, - minFilter: this.sourceTexture.minFilter, - type: this.sourceTexture.type, - generateMipmaps: this.sourceTexture.generateMipmaps, - anisotropy: this.sourceTexture.anisotropy, - encoding: this.sourceTexture.encoding + magFilter: THREE.NearestFilter, + minFilter: THREE.NearestFilter, + generateMipmaps: false, + type: equirectangular ? equirectangular.type : THREE.UnsignedByteType, + format: equirectangular ? equirectangular.format : THREE.RGBEFormat, + encoding: equirectangular ? equirectangular.encoding : THREE.RGBEEncoding, + depthBuffer: false, + stencilBuffer: false }; + var cubeUVRenderTarget = _createRenderTarget( + { ...params, depthBuffer: ( equirectangular ? false : true ) } ); + _pingPongRenderTarget = _createRenderTarget( params ); + return cubeUVRenderTarget; + + } + + function _cleanup() { - // how many LODs fit in the given CubeUV Texture. - this.numLods = Math.log( size ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 + _pingPongRenderTarget.dispose(); + _renderer.setRenderTarget( null ); + var size = _renderer.getSize( new THREE.Vector2() ); + _renderer.setViewport( 0, 0, size.x, size.y ); - for ( var i = 0; i < this.numLods; i ++ ) { + } - var renderTarget = new THREE.WebGLRenderTargetCube( size, size, params ); - renderTarget.texture.name = "PMREMGenerator.cube" + i; - this.cubeLods.push( renderTarget ); - size = Math.max( 16, size / 2 ); + function _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { + + var fov = 90; + var aspect = 1; + var cubeCamera = new THREE.PerspectiveCamera( fov, aspect, near, far ); + var upSign = [ 1, 1, 1, 1, - 1, 1 ]; + var forwardSign = [ 1, 1, - 1, - 1, - 1, 1 ]; + + var gammaOutput = _renderer.gammaOutput; + var toneMapping = _renderer.toneMapping; + var toneMappingExposure = _renderer.toneMappingExposure; + var clearColor = _renderer.getClearColor(); + var clearAlpha = _renderer.getClearAlpha(); + + _renderer.toneMapping = THREE.LinearToneMapping; + _renderer.toneMappingExposure = 1.0; + _renderer.gammaOutput = false; + scene.scale.z *= - 1; + + var background = scene.background; + if ( background && background.isColor ) { + + background.convertSRGBToLinear(); + // Convert linear to RGBE + var maxComponent = Math.max( background.r, background.g, background.b ); + var fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 ); + background = background.multiplyScalar( Math.pow( 2.0, - fExp ) ); + var alpha = ( fExp + 128.0 ) / 255.0; + _renderer.setClearColor( background, alpha ); + scene.background = null; } - }; + _renderer.setRenderTarget( cubeUVRenderTarget ); + for ( var i = 0; i < 6; i ++ ) { - PMREMGenerator.prototype = { + var col = i % 3; + if ( col == 0 ) { - constructor: PMREMGenerator, + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - /* - * Prashant Sharma / spidersharma03: More thought and work is needed here. - * Right now it's a kind of a hack to use the previously convolved map to convolve the current one. - * I tried to use the original map to convolve all the lods, but for many textures(specially the high frequency) - * even a high number of samples(1024) dosen't lead to satisfactory results. - * By using the previous convolved maps, a lower number of samples are generally sufficient(right now 32, which - * gives okay results unless we see the reflection very carefully, or zoom in too much), however the math - * goes wrong as the distribution function tries to sample a larger area than what it should be. So I simply scaled - * the roughness by 0.9(totally empirical) to try to visually match the original result. - * The condition "if(i <5)" is also an attemt to make the result match the original result. - * This method requires the most amount of thinking I guess. Here is a paper which we could try to implement in future:: - * https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html - */ - update: function ( renderer ) { + } else if ( col == 1 ) { + + cubeCamera.up.set( 0, 0, upSign[ i ] ); + cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - // Texture should only be flipped for CubeTexture, not for - // a Texture created via THREE.WebGLRenderTargetCube. - var tFlip = ( this.sourceTexture.isCubeTexture ) ? - 1 : 1; + } else { - shader.defines[ 'SAMPLES_PER_LEVEL' ] = this.samplesPerLevel; - shader.uniforms[ 'faceIndex' ].value = 0; - shader.uniforms[ 'envMap' ].value = this.sourceTexture; - shader.envMap = this.sourceTexture; - shader.needsUpdate = true; + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); + + } + _setViewport( + col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX ); + _renderer.render( scene, cubeCamera ); - var gammaInput = renderer.gammaInput; - var gammaOutput = renderer.gammaOutput; - var toneMapping = renderer.toneMapping; - var toneMappingExposure = renderer.toneMappingExposure; - var currentRenderTarget = renderer.getRenderTarget(); + } - renderer.toneMapping = THREE.LinearToneMapping; - renderer.toneMappingExposure = 1.0; - renderer.gammaInput = false; - renderer.gammaOutput = false; + _renderer.toneMapping = toneMapping; + _renderer.toneMappingExposure = toneMappingExposure; + _renderer.gammaOutput = gammaOutput; + _renderer.setClearColor( clearColor, clearAlpha ); + scene.scale.z *= - 1; - for ( var i = 0; i < this.numLods; i ++ ) { + } - var r = i / ( this.numLods - 1 ); - shader.uniforms[ 'roughness' ].value = r * 0.9; // see comment above, pragmatic choice - // Only apply the tFlip for the first LOD - shader.uniforms[ 'tFlip' ].value = ( i == 0 ) ? tFlip : 1; - var size = this.cubeLods[ i ].width; - shader.uniforms[ 'mapSize' ].value = size; - this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] ); + function _textureToCubeUV( texture, cubeUVRenderTarget ) { - if ( i < 5 ) shader.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; + var scene = new THREE.Scene(); + if ( texture.isCubeTexture ) { - } + if ( _cubemapShader == null ) { - renderer.setRenderTarget( currentRenderTarget ); - renderer.toneMapping = toneMapping; - renderer.toneMappingExposure = toneMappingExposure; - renderer.gammaInput = gammaInput; - renderer.gammaOutput = gammaOutput; + _cubemapShader = _getCubemapShader(); - }, + } - renderToCubeMapTarget: function ( renderer, renderTarget ) { + } else { - for ( var i = 0; i < 6; i ++ ) { + if ( _equirectShader == null ) { - this.renderToCubeMapTargetFace( renderer, renderTarget, i ); + _equirectShader = _getEquirectShader(); } - }, + } + var material = texture.isCubeTexture ? _cubemapShader : _equirectShader; + scene.add( new THREE.Mesh( _lodPlanes[ 0 ], material ) ); + var uniforms = material.uniforms; - renderToCubeMapTargetFace: function ( renderer, renderTarget, faceIndex ) { + uniforms[ 'envMap' ].value = texture; + if ( ! texture.isCubeTexture ) { - shader.uniforms[ 'faceIndex' ].value = faceIndex; - renderer.setRenderTarget( renderTarget, faceIndex ); - renderer.clear(); - renderer.render( scene, camera ); + uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height ); - }, + } + uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ]; + uniforms[ 'outputEncoding' ].value = ENCODINGS[ texture.encoding ]; - dispose: function () { + _renderer.setRenderTarget( cubeUVRenderTarget ); + _setViewport( 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX ); + _renderer.render( scene, _flatCamera ); + + } + + function _createRenderTarget( params ) { + + var cubeUVRenderTarget = + new THREE.WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params ); + cubeUVRenderTarget.texture.mapping = THREE.CubeUVReflectionMapping; + cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; + return cubeUVRenderTarget; - for ( var i = 0, l = this.cubeLods.length; i < l; i ++ ) { + } + + function _setViewport( x, y, width, height ) { + + var dpr = _renderer.getPixelRatio(); + _renderer.setViewport( x / dpr, y / dpr, width / dpr, height / dpr ); + + } + + function _applyPMREM( cubeUVRenderTarget ) { + + var autoClear = _renderer.autoClear; + _renderer.autoClear = false; + + for ( var i = 1; i < TOTAL_LODS; i ++ ) { + + var sigma = Math.sqrt( + _sigmas[ i ] * _sigmas[ i ] - + _sigmas[ i - 1 ] * _sigmas[ i - 1 ] ); + var poleAxis = + _axisDirections[ ( i - 1 ) % _axisDirections.length ]; + _blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); + + } + + _renderer.autoClear = autoClear; + + } + + /** + * This is a two-pass Gaussian blur for a cubemap. Normally this is done + * vertically and horizontally, but this breaks down on a cube. Here we apply + * the blur latitudinally (around the poles), and then longitudinally (towards + * the poles) to approximate the orthogonally-separable blur. It is least + * accurate at the poles, but still does a decent job. + */ + function _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + + _halfBlur( + cubeUVRenderTarget, + _pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); + + _halfBlur( + _pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); - this.cubeLods[ i ].dispose(); + } + + function _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + + if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + + console.error( + 'blur direction must be either latitudinal or longitudinal!' ); + + } + + // Number of standard deviations at which to cut off the discrete approximation. + var STANDARD_DEVIATIONS = 3; + + var blurScene = new THREE.Scene(); + blurScene.add( new THREE.Mesh( _lodPlanes[ lodOut ], _blurMaterial ) ); + var blurUniforms = _blurMaterial.uniforms; + + var pixels = _sizeLods[ lodIn ] - 1; + var radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + var sigmaPixels = sigmaRadians / radiansPerPixel; + var samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; + + if ( samples > MAX_SAMPLES ) { + + console.warn( `sigmaRadians, ${ + sigmaRadians}, is too large and will clip, as it requested ${ + samples} samples when the maximum is set to ${MAX_SAMPLES}` ); + + } + + var weights = []; + var sum = 0; + for ( var i = 0; i < MAX_SAMPLES; ++ i ) { + + var x = i / sigmaPixels; + var weight = Math.exp( - x * x / 2 ); + weights.push( weight ); + if ( i == 0 ) { + + sum += weight; + + } else if ( i < samples ) { + + sum += 2 * weight; } - shader.dispose(); + } + weights = weights.map( w => w / sum ); - }, + blurUniforms[ 'envMap' ].value = targetIn.texture; + blurUniforms[ 'samples' ].value = samples; + blurUniforms[ 'weights' ].value = weights; + blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; + if ( poleAxis ) { - }; + blurUniforms[ 'poleAxis' ].value = poleAxis; + + } + blurUniforms[ 'dTheta' ].value = radiansPerPixel; + blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn; + blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; + blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; + + var outputSize = _sizeLods[ lodOut ]; + var x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize ); + var y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + + 2 * outputSize * + ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 ); - function getShader() { + _renderer.setRenderTarget( targetOut ); + _setViewport( x, y, 3 * outputSize, 2 * outputSize ); + _renderer.render( blurScene, _flatCamera ); - var shaderMaterial = new THREE.ShaderMaterial( { + } + + function _getBlurShader( maxSamples ) { + + var weights = new Float32Array( maxSamples ); + var poleAxis = new THREE.Vector3( 0, 1, 0 ); + var shaderMaterial = new THREE.RawShaderMaterial( { - defines: { - "SAMPLES_PER_LEVEL": 20, + defines: { 'n': maxSamples }, + + uniforms: { + 'envMap': { value: null }, + 'samples': { value: 1 }, + 'weights': { value: weights }, + 'latitudinal': { value: false }, + 'dTheta': { value: 0 }, + 'mipInt': { value: 0 }, + 'poleAxis': { value: poleAxis }, + 'inputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] } }, + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform sampler2D envMap; +uniform int samples; +uniform float weights[n]; +uniform bool latitudinal; +uniform float dTheta; +uniform float mipInt; +uniform vec3 poleAxis; + +${_getEncodings()} + +#define ENVMAP_TYPE_CUBE_UV +#include + +void main() { + gl_FragColor = vec4(0.0); + for (int i = 0; i < n; i++) { + if (i >= samples) + break; + for (int dir = -1; dir < 2; dir += 2) { + if (i == 0 && dir == 1) + continue; + vec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection); + if (all(equal(axis, vec3(0.0)))) + axis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection); + axis = normalize(axis); + float theta = dTheta * float(dir * i); + float cosTheta = cos(theta); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross(axis, vOutputDirection) * sin(theta) + + axis * dot(axis, vOutputDirection) * (1.0 - cosTheta); + gl_FragColor.rgb += + weights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt); + } + } + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: THREE.NoBlending, + depthTest: false, + depthWrite: false + + } ); + + shaderMaterial.type = 'SphericalGaussianBlur'; + + return shaderMaterial; + + } + + function _getEquirectShader() { + + var texelSize = new THREE.Vector2( 1, 1 ); + var shaderMaterial = new THREE.RawShaderMaterial( { + uniforms: { - "faceIndex": { value: 0 }, - "roughness": { value: 0.5 }, - "mapSize": { value: 0.5 }, - "envMap": { value: null }, - "tFlip": { value: - 1 }, + 'envMap': { value: null }, + 'texelSize': { value: texelSize }, + 'inputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] } }, - vertexShader: - "varying vec2 vUv;\n\ - void main() {\n\ - vUv = uv;\n\ - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ - }", - - fragmentShader: - "#include \n\ - varying vec2 vUv;\n\ - uniform int faceIndex;\n\ - uniform float roughness;\n\ - uniform samplerCube envMap;\n\ - uniform float mapSize;\n\ - uniform float tFlip;\n\ - \n\ - float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\ - float a = ggxRoughness + 0.0001;\n\ - a *= a;\n\ - return ( 2.0 / a - 2.0 );\n\ - }\n\ - vec3 ImportanceSamplePhong(vec2 uv, mat3 vecSpace, float specPow) {\n\ - float phi = uv.y * 2.0 * PI;\n\ - float cosTheta = pow(1.0 - uv.x, 1.0 / (specPow + 1.0));\n\ - float sinTheta = sqrt(1.0 - cosTheta * cosTheta);\n\ - vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\n\ - return vecSpace * sampleDir;\n\ - }\n\ - vec3 ImportanceSampleGGX( vec2 uv, mat3 vecSpace, float Roughness )\n\ - {\n\ - float a = Roughness * Roughness;\n\ - float Phi = 2.0 * PI * uv.x;\n\ - float CosTheta = sqrt( (1.0 - uv.y) / ( 1.0 + (a*a - 1.0) * uv.y ) );\n\ - float SinTheta = sqrt( 1.0 - CosTheta * CosTheta );\n\ - return vecSpace * vec3(SinTheta * cos( Phi ), SinTheta * sin( Phi ), CosTheta);\n\ - }\n\ - mat3 matrixFromVector(vec3 n) {\n\ - float a = 1.0 / (1.0 + n.z);\n\ - float b = -n.x * n.y * a;\n\ - vec3 b1 = vec3(1.0 - n.x * n.x * a, b, -n.x);\n\ - vec3 b2 = vec3(b, 1.0 - n.y * n.y * a, -n.y);\n\ - return mat3(b1, b2, n);\n\ - }\n\ - \n\ - vec4 testColorMap(float Roughness) {\n\ - vec4 color;\n\ - if(faceIndex == 0)\n\ - color = vec4(1.0,0.0,0.0,1.0);\n\ - else if(faceIndex == 1)\n\ - color = vec4(0.0,1.0,0.0,1.0);\n\ - else if(faceIndex == 2)\n\ - color = vec4(0.0,0.0,1.0,1.0);\n\ - else if(faceIndex == 3)\n\ - color = vec4(1.0,1.0,0.0,1.0);\n\ - else if(faceIndex == 4)\n\ - color = vec4(0.0,1.0,1.0,1.0);\n\ - else\n\ - color = vec4(1.0,0.0,1.0,1.0);\n\ - color *= ( 1.0 - Roughness );\n\ - return color;\n\ - }\n\ - void main() {\n\ - vec3 sampleDirection;\n\ - vec2 uv = vUv*2.0 - 1.0;\n\ - float offset = -1.0/mapSize;\n\ - const float a = -1.0;\n\ - const float b = 1.0;\n\ - float c = -1.0 + offset;\n\ - float d = 1.0 - offset;\n\ - float bminusa = b - a;\n\ - uv.x = (uv.x - a)/bminusa * d - (uv.x - b)/bminusa * c;\n\ - uv.y = (uv.y - a)/bminusa * d - (uv.y - b)/bminusa * c;\n\ - if (faceIndex==0) {\n\ - sampleDirection = vec3(1.0, -uv.y, -uv.x);\n\ - } else if (faceIndex==1) {\n\ - sampleDirection = vec3(-1.0, -uv.y, uv.x);\n\ - } else if (faceIndex==2) {\n\ - sampleDirection = vec3(uv.x, 1.0, uv.y);\n\ - } else if (faceIndex==3) {\n\ - sampleDirection = vec3(uv.x, -1.0, -uv.y);\n\ - } else if (faceIndex==4) {\n\ - sampleDirection = vec3(uv.x, -uv.y, 1.0);\n\ - } else {\n\ - sampleDirection = vec3(-uv.x, -uv.y, -1.0);\n\ - }\n\ - vec3 correctedDirection = vec3( tFlip * sampleDirection.x, sampleDirection.yz );\n\ - mat3 vecSpace = matrixFromVector( normalize( correctedDirection ) );\n\ - vec3 rgbColor = vec3(0.0);\n\ - const int NumSamples = SAMPLES_PER_LEVEL;\n\ - vec3 vect;\n\ - float weight = 0.0;\n\ - for( int i = 0; i < NumSamples; i ++ ) {\n\ - float sini = sin(float(i));\n\ - float cosi = cos(float(i));\n\ - float r = rand(vec2(sini, cosi));\n\ - vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), r), vecSpace, roughness);\n\ - float dotProd = dot(vect, normalize(sampleDirection));\n\ - weight += dotProd;\n\ - vec3 color = envMapTexelToLinear(textureCube(envMap, vect)).rgb;\n\ - rgbColor.rgb += color;\n\ - }\n\ - rgbColor /= float(NumSamples);\n\ - //rgbColor = testColorMap( roughness ).rgb;\n\ - gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\ - }", - - blending: THREE.NoBlending + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform sampler2D envMap; +uniform vec2 texelSize; + +${_getEncodings()} + +#define RECIPROCAL_PI 0.31830988618 +#define RECIPROCAL_PI2 0.15915494 + +void main() { + gl_FragColor = vec4(0.0); + vec3 outputDirection = normalize(vOutputDirection); + vec2 uv; + uv.y = asin(clamp(outputDirection.y, -1.0, 1.0)) * RECIPROCAL_PI + 0.5; + uv.x = atan(outputDirection.z, outputDirection.x) * RECIPROCAL_PI2 + 0.5; + vec2 f = fract(uv / texelSize - 0.5); + uv -= f * texelSize; + vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.x += texelSize.x; + vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.y += texelSize.y; + vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.x -= texelSize.x; + vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + vec3 tm = mix(tl, tr, f.x); + vec3 bm = mix(bl, br, f.x); + gl_FragColor.rgb = mix(tm, bm, f.y); + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: THREE.NoBlending, + depthTest: false, + depthWrite: false } ); - shaderMaterial.type = 'PMREMGenerator'; + shaderMaterial.type = 'EquirectangularToCubeUV'; return shaderMaterial; } + function _getCubemapShader() { + + var shaderMaterial = new THREE.RawShaderMaterial( { + + uniforms: { + 'envMap': { value: null }, + 'inputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] } + }, + + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform samplerCube envMap; + +${_getEncodings()} + +void main() { + gl_FragColor = vec4(0.0); + gl_FragColor.rgb = envMapTexelToLinear(textureCube(envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ))).rgb; + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: THREE.NoBlending, + depthTest: false, + depthWrite: false + + } ); + + shaderMaterial.type = 'CubemapToCubeUV'; + + return shaderMaterial; + + } + + function _getCommonVertexShader() { + + return ` +precision mediump float; +precision mediump int; +attribute vec3 position; +attribute vec2 uv; +attribute float faceIndex; +varying vec3 vOutputDirection; +vec3 getDirection(vec2 uv, float face) { + uv = 2.0 * uv - 1.0; + vec3 direction = vec3(uv, 1.0); + if (face == 0.0) { + direction = direction.zyx; + direction.z *= -1.0; + } else if (face == 1.0) { + direction = direction.xzy; + direction.z *= -1.0; + } else if (face == 3.0) { + direction = direction.zyx; + direction.x *= -1.0; + } else if (face == 4.0) { + direction = direction.xzy; + direction.y *= -1.0; + } else if (face == 5.0) { + direction.xz *= -1.0; + } + return direction; +} +void main() { + vOutputDirection = getDirection(uv, faceIndex); + gl_Position = vec4( position, 1.0 ); +} + `; + + } + + function _getEncodings() { + + return ` +uniform int inputEncoding; +uniform int outputEncoding; + +#include + +vec4 inputTexelToLinear(vec4 value){ + if(inputEncoding == 0){ + return value; + }else if(inputEncoding == 1){ + return sRGBToLinear(value); + }else if(inputEncoding == 2){ + return RGBEToLinear(value); + }else if(inputEncoding == 3){ + return RGBMToLinear(value, 7.0); + }else if(inputEncoding == 4){ + return RGBMToLinear(value, 16.0); + }else if(inputEncoding == 5){ + return RGBDToLinear(value, 256.0); + }else{ + return GammaToLinear(value, 2.2); + } +} + +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); +} + `; + + } + return PMREMGenerator; } )(); diff --git a/examples/jsm/pmrem/PMREMCubeUVPacker.d.ts b/examples/jsm/pmrem/PMREMCubeUVPacker.d.ts deleted file mode 100644 index 16df9130e23d0e9b8af4d653ae6146d3591c9610..0000000000000000000000000000000000000000 --- a/examples/jsm/pmrem/PMREMCubeUVPacker.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CubeTexture, Renderer, WebGLRenderTarget } from '../../../src/Three'; - -export class PMREMCubeUVPacker { - - CubeUVRenderTarget:WebGLRenderTarget; - - constructor( cubeTextureLods: CubeTexture[] ); - update( renderer:Renderer ): void; - dispose(): void; - -} diff --git a/examples/jsm/pmrem/PMREMCubeUVPacker.js b/examples/jsm/pmrem/PMREMCubeUVPacker.js deleted file mode 100644 index 3fa44199a14c7025f8af59b08ceb38cd1a7908cd..0000000000000000000000000000000000000000 --- a/examples/jsm/pmrem/PMREMCubeUVPacker.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * @author Prashant Sharma / spidersharma03 - * @author Ben Houston / bhouston, https://clara.io - * - * This class takes the cube lods(corresponding to different roughness values), and creates a single cubeUV - * Texture. The format for a given roughness set of faces is simply:: - * +X+Y+Z - * -X-Y-Z - * For every roughness a mip map chain is also saved, which is essential to remove the texture artifacts due to - * minification. - * Right now for every face a PlaneMesh is drawn, which leads to a lot of geometry draw calls, but can be replaced - * later by drawing a single buffer and by sending the appropriate faceIndex via vertex attributes. - * The arrangement of the faces is fixed, as assuming this arrangement, the sampling function has been written. - */ - -import { - BackSide, - CubeUVReflectionMapping, - LinearFilter, - LinearToneMapping, - Mesh, - NoBlending, - OrthographicCamera, - PlaneBufferGeometry, - RGBEEncoding, - RGBM16Encoding, - Scene, - ShaderMaterial, - Vector2, - Vector3, - WebGLRenderTarget -} from "../../../build/three.module.js"; - -var PMREMCubeUVPacker = ( function () { - - var camera = new OrthographicCamera(); - var scene = new Scene(); - var shader = getShader(); - - var PMREMCubeUVPacker = function ( cubeTextureLods ) { - - this.cubeLods = cubeTextureLods; - var size = cubeTextureLods[ 0 ].width * 4; - - var sourceTexture = cubeTextureLods[ 0 ].texture; - var params = { - format: sourceTexture.format, - magFilter: sourceTexture.magFilter, - minFilter: sourceTexture.minFilter, - type: sourceTexture.type, - generateMipmaps: sourceTexture.generateMipmaps, - anisotropy: sourceTexture.anisotropy, - encoding: ( sourceTexture.encoding === RGBEEncoding ) ? RGBM16Encoding : sourceTexture.encoding - }; - - if ( params.encoding === RGBM16Encoding ) { - - params.magFilter = LinearFilter; - params.minFilter = LinearFilter; - - } - - this.CubeUVRenderTarget = new WebGLRenderTarget( size, size, params ); - this.CubeUVRenderTarget.texture.name = "PMREMCubeUVPacker.cubeUv"; - this.CubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - - this.objects = []; - - var geometry = new PlaneBufferGeometry( 1, 1 ); - - var faceOffsets = []; - faceOffsets.push( new Vector2( 0, 0 ) ); - faceOffsets.push( new Vector2( 1, 0 ) ); - faceOffsets.push( new Vector2( 2, 0 ) ); - faceOffsets.push( new Vector2( 0, 1 ) ); - faceOffsets.push( new Vector2( 1, 1 ) ); - faceOffsets.push( new Vector2( 2, 1 ) ); - - var textureResolution = size; - size = cubeTextureLods[ 0 ].width; - - var offset2 = 0; - var c = 4.0; - this.numLods = Math.log( cubeTextureLods[ 0 ].width ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 - for ( var i = 0; i < this.numLods; i ++ ) { - - var offset1 = ( textureResolution - textureResolution / c ) * 0.5; - if ( size > 16 ) c *= 2; - var nMips = size > 16 ? 6 : 1; - var mipOffsetX = 0; - var mipOffsetY = 0; - var mipSize = size; - - for ( var j = 0; j < nMips; j ++ ) { - - // Mip Maps - for ( var k = 0; k < 6; k ++ ) { - - // 6 Cube Faces - var material = shader.clone(); - material.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; - material.envMap = this.cubeLods[ i ].texture; - material.uniforms[ 'faceIndex' ].value = k; - material.uniforms[ 'mapSize' ].value = mipSize; - - var planeMesh = new Mesh( geometry, material ); - planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX; - planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY; - planeMesh.material.side = BackSide; - planeMesh.scale.setScalar( mipSize ); - this.objects.push( planeMesh ); - - } - mipOffsetY += 1.75 * mipSize; - mipOffsetX += 1.25 * mipSize; - mipSize /= 2; - - } - offset2 += 2 * size; - if ( size > 16 ) size /= 2; - - } - - }; - - PMREMCubeUVPacker.prototype = { - - constructor: PMREMCubeUVPacker, - - update: function ( renderer ) { - - var size = this.cubeLods[ 0 ].width * 4; - // top and bottom are swapped for some reason? - camera.left = - size * 0.5; - camera.right = size * 0.5; - camera.top = - size * 0.5; - camera.bottom = size * 0.5; - camera.near = 0; - camera.far = 1; - camera.updateProjectionMatrix(); - - for ( var i = 0; i < this.objects.length; i ++ ) { - - scene.add( this.objects[ i ] ); - - } - - var gammaInput = renderer.gammaInput; - var gammaOutput = renderer.gammaOutput; - var toneMapping = renderer.toneMapping; - var toneMappingExposure = renderer.toneMappingExposure; - var currentRenderTarget = renderer.getRenderTarget(); - - renderer.gammaInput = false; - renderer.gammaOutput = false; - renderer.toneMapping = LinearToneMapping; - renderer.toneMappingExposure = 1.0; - renderer.setRenderTarget( this.CubeUVRenderTarget ); - renderer.render( scene, camera ); - - renderer.setRenderTarget( currentRenderTarget ); - renderer.toneMapping = toneMapping; - renderer.toneMappingExposure = toneMappingExposure; - renderer.gammaInput = gammaInput; - renderer.gammaOutput = gammaOutput; - - for ( var i = 0; i < this.objects.length; i ++ ) { - - scene.remove( this.objects[ i ] ); - - } - - }, - - dispose: function () { - - for ( var i = 0, l = this.objects.length; i < l; i ++ ) { - - this.objects[ i ].material.dispose(); - - } - - this.objects[ 0 ].geometry.dispose(); - - } - - }; - - function getShader() { - - var shaderMaterial = new ShaderMaterial( { - - uniforms: { - "faceIndex": { value: 0 }, - "mapSize": { value: 0 }, - "envMap": { value: null }, - "testColor": { value: new Vector3( 1, 1, 1 ) } - }, - - vertexShader: - "precision highp float;\ - varying vec2 vUv;\ - void main() {\ - vUv = uv;\ - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\ - }", - - fragmentShader: - "precision highp float;\ - varying vec2 vUv;\ - uniform samplerCube envMap;\ - uniform float mapSize;\ - uniform vec3 testColor;\ - uniform int faceIndex;\ - \ - void main() {\ - vec3 sampleDirection;\ - vec2 uv = vUv;\ - uv = uv * 2.0 - 1.0;\ - uv.y *= -1.0;\ - if(faceIndex == 0) {\ - sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\ - } else if(faceIndex == 1) {\ - sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\ - } else if(faceIndex == 2) {\ - sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\ - } else if(faceIndex == 3) {\ - sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\ - } else if(faceIndex == 4) {\ - sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\ - } else {\ - sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\ - }\ - vec4 color = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\ - gl_FragColor = linearToOutputTexel( color );\ - }", - - blending: NoBlending - - } ); - - shaderMaterial.type = 'PMREMCubeUVPacker'; - - return shaderMaterial; - - } - - - return PMREMCubeUVPacker; - -} )(); - -export { PMREMCubeUVPacker }; diff --git a/examples/jsm/pmrem/PMREMGenerator.d.ts b/examples/jsm/pmrem/PMREMGenerator.d.ts index 568ada2b0a2084bd15010008ba151fbe675bbe12..2d337821032fe6995ea9ecf0a5a543d3446f18f8 100644 --- a/examples/jsm/pmrem/PMREMGenerator.d.ts +++ b/examples/jsm/pmrem/PMREMGenerator.d.ts @@ -1,18 +1,17 @@ import { - Renderer, - RenderTarget, + WebGLRenderer, + WebGLRenderTarget, Texture, - CubeTexture + CubeTexture, + Scene } from '../../../src/Three'; export class PMREMGenerator { - cubeLods:CubeTexture[]; - - constructor( sourceTexture:Texture, samplesPerLevel?:number, resolution?:number ); - update( renderer:Renderer ): void; - renderToCubeMapTarget( renderer:Renderer, renderTarget:any ): void; - renderToCubeMapTargetFace( renderer:Renderer, renderTarget:RenderTarget, faceIndex:number ): void; + constructor( renderer:WebGLRenderer ); + fromScene( scene:Scene, sigma?:number, near?:number, far?:number ): WebGLRenderTarget; + fromEquirectangular( equirectangular:Texture ): WebGLRenderTarget; + fromCubemap( cubemap:CubeTexture ): WebGLRenderTarget; dispose(): void; } diff --git a/examples/jsm/pmrem/PMREMGenerator.js b/examples/jsm/pmrem/PMREMGenerator.js index 335e019a3d597d4fd16f089f6484bd603936817c..28c32b0062ca149fc7aaefb0124b8000bce769a3 100644 --- a/examples/jsm/pmrem/PMREMGenerator.js +++ b/examples/jsm/pmrem/PMREMGenerator.js @@ -1,310 +1,793 @@ /** - * @author Prashant Sharma / spidersharma03 - * @author Ben Houston / bhouston, https://clara.io + * @author Emmett Lalish / elalish * - * To avoid cube map seams, I create an extra pixel around each face. This way when the cube map is - * sampled by an application later(with a little care by sampling the centre of the texel), the extra 1 border - * of pixels makes sure that there is no seams artifacts present. This works perfectly for cubeUV format as - * well where the 6 faces can be arranged in any manner whatsoever. - * Code in the beginning of fragment shader's main function does this job for a given resolution. - * Run Scene_PMREM_Test.html in the examples directory to see the sampling from the cube lods generated - * by this class. + * This class generates a Prefiltered, Mipmapped Radiance Environment Map + * (PMREM) from a cubeMap environment texture. This allows different levels of + * blur to be quickly accessed based on material roughness. It is packed into a + * special CubeUV format that allows us to perform custom interpolation so that + * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap + * chain, it only goes down to the LOD_MIN level (above), and then creates extra + * even more filtered 'mips' at the same LOD_MIN resolution, associated with + * higher roughness levels. In this way we maintain resolution to smoothly + * interpolate diffuse lighting while limiting sampling computation. */ import { - DoubleSide, + BufferAttribute, + BufferGeometry, + CubeUVReflectionMapping, GammaEncoding, LinearEncoding, - LinearFilter, LinearToneMapping, Mesh, NearestFilter, NoBlending, OrthographicCamera, - PlaneBufferGeometry, + PerspectiveCamera, + RGBDEncoding, + RGBEEncoding, + RGBEFormat, + RGBM16Encoding, + RGBM7Encoding, + RawShaderMaterial, Scene, - ShaderMaterial, - WebGLRenderTargetCube, + UnsignedByteType, + Vector2, + Vector3, + WebGLRenderTarget, sRGBEncoding } from "../../../build/three.module.js"; var PMREMGenerator = ( function () { - var shader = getShader(); - var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0.0, 1000 ); - var scene = new Scene(); - var planeMesh = new Mesh( new PlaneBufferGeometry( 2, 2, 0 ), shader ); - planeMesh.material.side = DoubleSide; - scene.add( planeMesh ); - scene.add( camera ); + var LOD_MIN = 4; + var LOD_MAX = 8; + var SIZE_MAX = Math.pow( 2, LOD_MAX ); + // The standard deviations (radians) associated with the extra mips. These are + // chosen to approximate a Trowbridge-Reitz distribution function times the + // geometric shadowing function. These sigma values squared must match the + // variance #defines in cube_uv_reflection_fragment.glsl.js. + var EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + var TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; + // The maximum length of the blur for loop. Smaller sigmas will use fewer + // samples and exit early, but not recompile the shader. + var MAX_SAMPLES = 20; + var ENCODINGS = { + [ LinearEncoding ]: 0, + [ sRGBEncoding ]: 1, + [ RGBEEncoding ]: 2, + [ RGBM7Encoding ]: 3, + [ RGBM16Encoding ]: 4, + [ RGBDEncoding ]: 5, + [ GammaEncoding ]: 6 + }; + + var _flatCamera = new OrthographicCamera(); + var _blurMaterial = _getBlurShader( MAX_SAMPLES ); + var _equirectShader = null; + var _cubemapShader = null; + + var { _lodPlanes, _sizeLods, _sigmas } = _createPlanes(); + var _pingPongRenderTarget = null; + var _renderer = null; + + // Golden Ratio + var PHI = ( 1 + Math.sqrt( 5 ) ) / 2; + var INV_PHI = 1 / PHI; + // Vertices of a dodecahedron (except the opposites, which represent the + // same axis), used as axis directions evenly spread on a sphere. + var _axisDirections = [ + new Vector3( 1, 1, 1 ), + new Vector3( - 1, 1, 1 ), + new Vector3( 1, 1, - 1 ), + new Vector3( - 1, 1, - 1 ), + new Vector3( 0, PHI, INV_PHI ), + new Vector3( 0, PHI, - INV_PHI ), + new Vector3( INV_PHI, 0, PHI ), + new Vector3( - INV_PHI, 0, PHI ), + new Vector3( PHI, INV_PHI, 0 ), + new Vector3( - PHI, INV_PHI, 0 ) ]; + + var PMREMGenerator = function ( renderer ) { + + _renderer = renderer; - var PMREMGenerator = function ( sourceTexture, samplesPerLevel, resolution ) { + }; + + PMREMGenerator.prototype = { + + constructor: PMREMGenerator, + + /** + * Generates a PMREM from a supplied Scene, which can be faster than using an + * image if networking bandwidth is low. Optional sigma specifies a blur radius + * in radians to be applied to the scene before PMREM generation. Optional near + * and far planes ensure the scene is rendered in its entirety (the cubeCamera + * is placed at the origin). + */ + fromScene: function ( scene, sigma = 0, near = 0.1, far = 100 ) { + + var cubeUVRenderTarget = _allocateTargets(); + _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + if ( sigma > 0 ) { + + _blur( cubeUVRenderTarget, 0, 0, sigma ); + + } + _applyPMREM( cubeUVRenderTarget ); + _cleanup(); + + return cubeUVRenderTarget; + + }, + + /** + * Generates a PMREM from an equirectangular texture, which can be either LDR + * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512), + * as this matches best with the 256 x 256 cubemap output. + */ + fromEquirectangular: function ( equirectangular ) { + + equirectangular.magFilter = NearestFilter; + equirectangular.minFilter = NearestFilter; + equirectangular.generateMipmaps = false; + + return this.fromCubemap( equirectangular ); + + }, + + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256, + * as this matches best with the 256 x 256 cubemap output. + */ + fromCubemap: function ( cubemap ) { + + var cubeUVRenderTarget = _allocateTargets( cubemap ); + _textureToCubeUV( cubemap, cubeUVRenderTarget ); + _applyPMREM( cubeUVRenderTarget ); + _cleanup(); + + return cubeUVRenderTarget; + + }, + + /** + * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, + * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on + * one of them will cause any others to also become unusable. + */ + dispose: function () { + + _blurMaterial.dispose(); + if ( _cubemapShader != null ) _cubemapShader.dispose(); + if ( _equirectShader != null ) _equirectShader.dispose(); + var plane; + for ( plane of _lodPlanes ) { + + plane.dispose(); + + } + + }, + + }; + + function _createPlanes() { + + var _lodPlanes = []; + var _sizeLods = []; + var _sigmas = []; - this.sourceTexture = sourceTexture; - this.resolution = ( resolution !== undefined ) ? resolution : 256; // NODE: 256 is currently hard coded in the glsl code for performance reasons - this.samplesPerLevel = ( samplesPerLevel !== undefined ) ? samplesPerLevel : 32; + var lod = LOD_MAX; + for ( var i = 0; i < TOTAL_LODS; i ++ ) { - var monotonicEncoding = ( this.sourceTexture.encoding === LinearEncoding ) || - ( this.sourceTexture.encoding === GammaEncoding ) || ( this.sourceTexture.encoding === sRGBEncoding ); + var sizeLod = Math.pow( 2, lod ); + _sizeLods.push( sizeLod ); + var sigma = 1.0 / sizeLod; + if ( i > LOD_MAX - LOD_MIN ) { - this.sourceTexture.minFilter = ( monotonicEncoding ) ? LinearFilter : NearestFilter; - this.sourceTexture.magFilter = ( monotonicEncoding ) ? LinearFilter : NearestFilter; - this.sourceTexture.generateMipmaps = this.sourceTexture.generateMipmaps && monotonicEncoding; + sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ]; - this.cubeLods = []; + } else if ( i == 0 ) { + + sigma = 0; + + } + _sigmas.push( sigma ); + + var texelSize = 1.0 / ( sizeLod - 1 ); + var min = - texelSize / 2; + var max = 1 + texelSize / 2; + var uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + + var cubeFaces = 6; + var vertices = 6; + var positionSize = 3; + var uvSize = 2; + var faceIndexSize = 1; + + var position = new Float32Array( positionSize * vertices * cubeFaces ); + var uv = new Float32Array( uvSize * vertices * cubeFaces ); + var faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + + for ( var face = 0; face < cubeFaces; face ++ ) { + + var x = ( face % 3 ) * 2 / 3 - 1; + var y = face > 2 ? 0 : - 1; + var coordinates = [ + [ x, y, 0 ], + [ x + 2 / 3, y, 0 ], + [ x + 2 / 3, y + 1, 0 ], + [ x, y, 0 ], + [ x + 2 / 3, y + 1, 0 ], + [ x, y + 1, 0 ] + ]; + position.set( [].concat( ...coordinates ), + positionSize * vertices * face ); + uv.set( uv1, uvSize * vertices * face ); + var fill = [ face, face, face, face, face, face ]; + faceIndex.set( fill, faceIndexSize * vertices * face ); + + } + var planes = new BufferGeometry(); + planes.setAttribute( + 'position', new BufferAttribute( position, positionSize ) ); + planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); + planes.setAttribute( + 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); + _lodPlanes.push( planes ); + + if ( lod > LOD_MIN ) { + + lod --; + + } + + } + return { _lodPlanes, _sizeLods, _sigmas }; + + } + + function _allocateTargets( equirectangular ) { - var size = this.resolution; var params = { - format: this.sourceTexture.format, - magFilter: this.sourceTexture.magFilter, - minFilter: this.sourceTexture.minFilter, - type: this.sourceTexture.type, - generateMipmaps: this.sourceTexture.generateMipmaps, - anisotropy: this.sourceTexture.anisotropy, - encoding: this.sourceTexture.encoding + magFilter: NearestFilter, + minFilter: NearestFilter, + generateMipmaps: false, + type: equirectangular ? equirectangular.type : UnsignedByteType, + format: equirectangular ? equirectangular.format : RGBEFormat, + encoding: equirectangular ? equirectangular.encoding : RGBEEncoding, + depthBuffer: false, + stencilBuffer: false }; + var cubeUVRenderTarget = _createRenderTarget( + { ...params, depthBuffer: ( equirectangular ? false : true ) } ); + _pingPongRenderTarget = _createRenderTarget( params ); + return cubeUVRenderTarget; + + } + + function _cleanup() { - // how many LODs fit in the given CubeUV Texture. - this.numLods = Math.log( size ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 + _pingPongRenderTarget.dispose(); + _renderer.setRenderTarget( null ); + var size = _renderer.getSize( new Vector2() ); + _renderer.setViewport( 0, 0, size.x, size.y ); - for ( var i = 0; i < this.numLods; i ++ ) { + } - var renderTarget = new WebGLRenderTargetCube( size, size, params ); - renderTarget.texture.name = "PMREMGenerator.cube" + i; - this.cubeLods.push( renderTarget ); - size = Math.max( 16, size / 2 ); + function _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { + + var fov = 90; + var aspect = 1; + var cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); + var upSign = [ 1, 1, 1, 1, - 1, 1 ]; + var forwardSign = [ 1, 1, - 1, - 1, - 1, 1 ]; + + var gammaOutput = _renderer.gammaOutput; + var toneMapping = _renderer.toneMapping; + var toneMappingExposure = _renderer.toneMappingExposure; + var clearColor = _renderer.getClearColor(); + var clearAlpha = _renderer.getClearAlpha(); + + _renderer.toneMapping = LinearToneMapping; + _renderer.toneMappingExposure = 1.0; + _renderer.gammaOutput = false; + scene.scale.z *= - 1; + + var background = scene.background; + if ( background && background.isColor ) { + + background.convertSRGBToLinear(); + // Convert linear to RGBE + var maxComponent = Math.max( background.r, background.g, background.b ); + var fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 ); + background = background.multiplyScalar( Math.pow( 2.0, - fExp ) ); + var alpha = ( fExp + 128.0 ) / 255.0; + _renderer.setClearColor( background, alpha ); + scene.background = null; } - }; + _renderer.setRenderTarget( cubeUVRenderTarget ); + for ( var i = 0; i < 6; i ++ ) { - PMREMGenerator.prototype = { + var col = i % 3; + if ( col == 0 ) { - constructor: PMREMGenerator, + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - /* - * Prashant Sharma / spidersharma03: More thought and work is needed here. - * Right now it's a kind of a hack to use the previously convolved map to convolve the current one. - * I tried to use the original map to convolve all the lods, but for many textures(specially the high frequency) - * even a high number of samples(1024) dosen't lead to satisfactory results. - * By using the previous convolved maps, a lower number of samples are generally sufficient(right now 32, which - * gives okay results unless we see the reflection very carefully, or zoom in too much), however the math - * goes wrong as the distribution function tries to sample a larger area than what it should be. So I simply scaled - * the roughness by 0.9(totally empirical) to try to visually match the original result. - * The condition "if(i <5)" is also an attemt to make the result match the original result. - * This method requires the most amount of thinking I guess. Here is a paper which we could try to implement in future:: - * https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html - */ - update: function ( renderer ) { + } else if ( col == 1 ) { + + cubeCamera.up.set( 0, 0, upSign[ i ] ); + cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - // Texture should only be flipped for CubeTexture, not for - // a Texture created via WebGLRenderTargetCube. - var tFlip = ( this.sourceTexture.isCubeTexture ) ? - 1 : 1; + } else { - shader.defines[ 'SAMPLES_PER_LEVEL' ] = this.samplesPerLevel; - shader.uniforms[ 'faceIndex' ].value = 0; - shader.uniforms[ 'envMap' ].value = this.sourceTexture; - shader.envMap = this.sourceTexture; - shader.needsUpdate = true; + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); + + } + _setViewport( + col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX ); + _renderer.render( scene, cubeCamera ); - var gammaInput = renderer.gammaInput; - var gammaOutput = renderer.gammaOutput; - var toneMapping = renderer.toneMapping; - var toneMappingExposure = renderer.toneMappingExposure; - var currentRenderTarget = renderer.getRenderTarget(); + } - renderer.toneMapping = LinearToneMapping; - renderer.toneMappingExposure = 1.0; - renderer.gammaInput = false; - renderer.gammaOutput = false; + _renderer.toneMapping = toneMapping; + _renderer.toneMappingExposure = toneMappingExposure; + _renderer.gammaOutput = gammaOutput; + _renderer.setClearColor( clearColor, clearAlpha ); + scene.scale.z *= - 1; - for ( var i = 0; i < this.numLods; i ++ ) { + } - var r = i / ( this.numLods - 1 ); - shader.uniforms[ 'roughness' ].value = r * 0.9; // see comment above, pragmatic choice - // Only apply the tFlip for the first LOD - shader.uniforms[ 'tFlip' ].value = ( i == 0 ) ? tFlip : 1; - var size = this.cubeLods[ i ].width; - shader.uniforms[ 'mapSize' ].value = size; - this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] ); + function _textureToCubeUV( texture, cubeUVRenderTarget ) { - if ( i < 5 ) shader.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; + var scene = new Scene(); + if ( texture.isCubeTexture ) { - } + if ( _cubemapShader == null ) { - renderer.setRenderTarget( currentRenderTarget ); - renderer.toneMapping = toneMapping; - renderer.toneMappingExposure = toneMappingExposure; - renderer.gammaInput = gammaInput; - renderer.gammaOutput = gammaOutput; + _cubemapShader = _getCubemapShader(); - }, + } - renderToCubeMapTarget: function ( renderer, renderTarget ) { + } else { - for ( var i = 0; i < 6; i ++ ) { + if ( _equirectShader == null ) { - this.renderToCubeMapTargetFace( renderer, renderTarget, i ); + _equirectShader = _getEquirectShader(); } - }, + } + var material = texture.isCubeTexture ? _cubemapShader : _equirectShader; + scene.add( new Mesh( _lodPlanes[ 0 ], material ) ); + var uniforms = material.uniforms; - renderToCubeMapTargetFace: function ( renderer, renderTarget, faceIndex ) { + uniforms[ 'envMap' ].value = texture; + if ( ! texture.isCubeTexture ) { - shader.uniforms[ 'faceIndex' ].value = faceIndex; - renderer.setRenderTarget( renderTarget, faceIndex ); - renderer.clear(); - renderer.render( scene, camera ); + uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height ); - }, + } + uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ]; + uniforms[ 'outputEncoding' ].value = ENCODINGS[ texture.encoding ]; - dispose: function () { + _renderer.setRenderTarget( cubeUVRenderTarget ); + _setViewport( 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX ); + _renderer.render( scene, _flatCamera ); + + } + + function _createRenderTarget( params ) { + + var cubeUVRenderTarget = + new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params ); + cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; + cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; + return cubeUVRenderTarget; - for ( var i = 0, l = this.cubeLods.length; i < l; i ++ ) { + } + + function _setViewport( x, y, width, height ) { + + var dpr = _renderer.getPixelRatio(); + _renderer.setViewport( x / dpr, y / dpr, width / dpr, height / dpr ); + + } + + function _applyPMREM( cubeUVRenderTarget ) { + + var autoClear = _renderer.autoClear; + _renderer.autoClear = false; + + for ( var i = 1; i < TOTAL_LODS; i ++ ) { + + var sigma = Math.sqrt( + _sigmas[ i ] * _sigmas[ i ] - + _sigmas[ i - 1 ] * _sigmas[ i - 1 ] ); + var poleAxis = + _axisDirections[ ( i - 1 ) % _axisDirections.length ]; + _blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); + + } + + _renderer.autoClear = autoClear; + + } + + /** + * This is a two-pass Gaussian blur for a cubemap. Normally this is done + * vertically and horizontally, but this breaks down on a cube. Here we apply + * the blur latitudinally (around the poles), and then longitudinally (towards + * the poles) to approximate the orthogonally-separable blur. It is least + * accurate at the poles, but still does a decent job. + */ + function _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + + _halfBlur( + cubeUVRenderTarget, + _pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); + + _halfBlur( + _pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); - this.cubeLods[ i ].dispose(); + } + + function _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + + if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + + console.error( + 'blur direction must be either latitudinal or longitudinal!' ); + + } + + // Number of standard deviations at which to cut off the discrete approximation. + var STANDARD_DEVIATIONS = 3; + + var blurScene = new Scene(); + blurScene.add( new Mesh( _lodPlanes[ lodOut ], _blurMaterial ) ); + var blurUniforms = _blurMaterial.uniforms; + + var pixels = _sizeLods[ lodIn ] - 1; + var radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + var sigmaPixels = sigmaRadians / radiansPerPixel; + var samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; + + if ( samples > MAX_SAMPLES ) { + + console.warn( `sigmaRadians, ${ + sigmaRadians}, is too large and will clip, as it requested ${ + samples} samples when the maximum is set to ${MAX_SAMPLES}` ); + + } + + var weights = []; + var sum = 0; + for ( var i = 0; i < MAX_SAMPLES; ++ i ) { + + var x = i / sigmaPixels; + var weight = Math.exp( - x * x / 2 ); + weights.push( weight ); + if ( i == 0 ) { + + sum += weight; + + } else if ( i < samples ) { + + sum += 2 * weight; } - shader.dispose(); + } + weights = weights.map( w => w / sum ); - }, + blurUniforms[ 'envMap' ].value = targetIn.texture; + blurUniforms[ 'samples' ].value = samples; + blurUniforms[ 'weights' ].value = weights; + blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; + if ( poleAxis ) { - }; + blurUniforms[ 'poleAxis' ].value = poleAxis; + + } + blurUniforms[ 'dTheta' ].value = radiansPerPixel; + blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn; + blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; + blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; + + var outputSize = _sizeLods[ lodOut ]; + var x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize ); + var y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + + 2 * outputSize * + ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 ); - function getShader() { + _renderer.setRenderTarget( targetOut ); + _setViewport( x, y, 3 * outputSize, 2 * outputSize ); + _renderer.render( blurScene, _flatCamera ); - var shaderMaterial = new ShaderMaterial( { + } + + function _getBlurShader( maxSamples ) { + + var weights = new Float32Array( maxSamples ); + var poleAxis = new Vector3( 0, 1, 0 ); + var shaderMaterial = new RawShaderMaterial( { - defines: { - "SAMPLES_PER_LEVEL": 20, + defines: { 'n': maxSamples }, + + uniforms: { + 'envMap': { value: null }, + 'samples': { value: 1 }, + 'weights': { value: weights }, + 'latitudinal': { value: false }, + 'dTheta': { value: 0 }, + 'mipInt': { value: 0 }, + 'poleAxis': { value: poleAxis }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } }, + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform sampler2D envMap; +uniform int samples; +uniform float weights[n]; +uniform bool latitudinal; +uniform float dTheta; +uniform float mipInt; +uniform vec3 poleAxis; + +${_getEncodings()} + +#define ENVMAP_TYPE_CUBE_UV +#include + +void main() { + gl_FragColor = vec4(0.0); + for (int i = 0; i < n; i++) { + if (i >= samples) + break; + for (int dir = -1; dir < 2; dir += 2) { + if (i == 0 && dir == 1) + continue; + vec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection); + if (all(equal(axis, vec3(0.0)))) + axis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection); + axis = normalize(axis); + float theta = dTheta * float(dir * i); + float cosTheta = cos(theta); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross(axis, vOutputDirection) * sin(theta) + + axis * dot(axis, vOutputDirection) * (1.0 - cosTheta); + gl_FragColor.rgb += + weights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt); + } + } + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: NoBlending, + depthTest: false, + depthWrite: false + + } ); + + shaderMaterial.type = 'SphericalGaussianBlur'; + + return shaderMaterial; + + } + + function _getEquirectShader() { + + var texelSize = new Vector2( 1, 1 ); + var shaderMaterial = new RawShaderMaterial( { + uniforms: { - "faceIndex": { value: 0 }, - "roughness": { value: 0.5 }, - "mapSize": { value: 0.5 }, - "envMap": { value: null }, - "tFlip": { value: - 1 }, + 'envMap': { value: null }, + 'texelSize': { value: texelSize }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } }, - vertexShader: - "varying vec2 vUv;\n\ - void main() {\n\ - vUv = uv;\n\ - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ - }", - - fragmentShader: - "#include \n\ - varying vec2 vUv;\n\ - uniform int faceIndex;\n\ - uniform float roughness;\n\ - uniform samplerCube envMap;\n\ - uniform float mapSize;\n\ - uniform float tFlip;\n\ - \n\ - float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\ - float a = ggxRoughness + 0.0001;\n\ - a *= a;\n\ - return ( 2.0 / a - 2.0 );\n\ - }\n\ - vec3 ImportanceSamplePhong(vec2 uv, mat3 vecSpace, float specPow) {\n\ - float phi = uv.y * 2.0 * PI;\n\ - float cosTheta = pow(1.0 - uv.x, 1.0 / (specPow + 1.0));\n\ - float sinTheta = sqrt(1.0 - cosTheta * cosTheta);\n\ - vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\n\ - return vecSpace * sampleDir;\n\ - }\n\ - vec3 ImportanceSampleGGX( vec2 uv, mat3 vecSpace, float Roughness )\n\ - {\n\ - float a = Roughness * Roughness;\n\ - float Phi = 2.0 * PI * uv.x;\n\ - float CosTheta = sqrt( (1.0 - uv.y) / ( 1.0 + (a*a - 1.0) * uv.y ) );\n\ - float SinTheta = sqrt( 1.0 - CosTheta * CosTheta );\n\ - return vecSpace * vec3(SinTheta * cos( Phi ), SinTheta * sin( Phi ), CosTheta);\n\ - }\n\ - mat3 matrixFromVector(vec3 n) {\n\ - float a = 1.0 / (1.0 + n.z);\n\ - float b = -n.x * n.y * a;\n\ - vec3 b1 = vec3(1.0 - n.x * n.x * a, b, -n.x);\n\ - vec3 b2 = vec3(b, 1.0 - n.y * n.y * a, -n.y);\n\ - return mat3(b1, b2, n);\n\ - }\n\ - \n\ - vec4 testColorMap(float Roughness) {\n\ - vec4 color;\n\ - if(faceIndex == 0)\n\ - color = vec4(1.0,0.0,0.0,1.0);\n\ - else if(faceIndex == 1)\n\ - color = vec4(0.0,1.0,0.0,1.0);\n\ - else if(faceIndex == 2)\n\ - color = vec4(0.0,0.0,1.0,1.0);\n\ - else if(faceIndex == 3)\n\ - color = vec4(1.0,1.0,0.0,1.0);\n\ - else if(faceIndex == 4)\n\ - color = vec4(0.0,1.0,1.0,1.0);\n\ - else\n\ - color = vec4(1.0,0.0,1.0,1.0);\n\ - color *= ( 1.0 - Roughness );\n\ - return color;\n\ - }\n\ - void main() {\n\ - vec3 sampleDirection;\n\ - vec2 uv = vUv*2.0 - 1.0;\n\ - float offset = -1.0/mapSize;\n\ - const float a = -1.0;\n\ - const float b = 1.0;\n\ - float c = -1.0 + offset;\n\ - float d = 1.0 - offset;\n\ - float bminusa = b - a;\n\ - uv.x = (uv.x - a)/bminusa * d - (uv.x - b)/bminusa * c;\n\ - uv.y = (uv.y - a)/bminusa * d - (uv.y - b)/bminusa * c;\n\ - if (faceIndex==0) {\n\ - sampleDirection = vec3(1.0, -uv.y, -uv.x);\n\ - } else if (faceIndex==1) {\n\ - sampleDirection = vec3(-1.0, -uv.y, uv.x);\n\ - } else if (faceIndex==2) {\n\ - sampleDirection = vec3(uv.x, 1.0, uv.y);\n\ - } else if (faceIndex==3) {\n\ - sampleDirection = vec3(uv.x, -1.0, -uv.y);\n\ - } else if (faceIndex==4) {\n\ - sampleDirection = vec3(uv.x, -uv.y, 1.0);\n\ - } else {\n\ - sampleDirection = vec3(-uv.x, -uv.y, -1.0);\n\ - }\n\ - vec3 correctedDirection = vec3( tFlip * sampleDirection.x, sampleDirection.yz );\n\ - mat3 vecSpace = matrixFromVector( normalize( correctedDirection ) );\n\ - vec3 rgbColor = vec3(0.0);\n\ - const int NumSamples = SAMPLES_PER_LEVEL;\n\ - vec3 vect;\n\ - float weight = 0.0;\n\ - for( int i = 0; i < NumSamples; i ++ ) {\n\ - float sini = sin(float(i));\n\ - float cosi = cos(float(i));\n\ - float r = rand(vec2(sini, cosi));\n\ - vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), r), vecSpace, roughness);\n\ - float dotProd = dot(vect, normalize(sampleDirection));\n\ - weight += dotProd;\n\ - vec3 color = envMapTexelToLinear(textureCube(envMap, vect)).rgb;\n\ - rgbColor.rgb += color;\n\ - }\n\ - rgbColor /= float(NumSamples);\n\ - //rgbColor = testColorMap( roughness ).rgb;\n\ - gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\ - }", - - blending: NoBlending + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform sampler2D envMap; +uniform vec2 texelSize; + +${_getEncodings()} + +#define RECIPROCAL_PI 0.31830988618 +#define RECIPROCAL_PI2 0.15915494 + +void main() { + gl_FragColor = vec4(0.0); + vec3 outputDirection = normalize(vOutputDirection); + vec2 uv; + uv.y = asin(clamp(outputDirection.y, -1.0, 1.0)) * RECIPROCAL_PI + 0.5; + uv.x = atan(outputDirection.z, outputDirection.x) * RECIPROCAL_PI2 + 0.5; + vec2 f = fract(uv / texelSize - 0.5); + uv -= f * texelSize; + vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.x += texelSize.x; + vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.y += texelSize.y; + vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + uv.x -= texelSize.x; + vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb; + vec3 tm = mix(tl, tr, f.x); + vec3 bm = mix(bl, br, f.x); + gl_FragColor.rgb = mix(tm, bm, f.y); + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: NoBlending, + depthTest: false, + depthWrite: false } ); - shaderMaterial.type = 'PMREMGenerator'; + shaderMaterial.type = 'EquirectangularToCubeUV'; return shaderMaterial; } + function _getCubemapShader() { + + var shaderMaterial = new RawShaderMaterial( { + + uniforms: { + 'envMap': { value: null }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } + }, + + vertexShader: _getCommonVertexShader(), + + fragmentShader: ` +precision mediump float; +precision mediump int; +varying vec3 vOutputDirection; +uniform samplerCube envMap; + +${_getEncodings()} + +void main() { + gl_FragColor = vec4(0.0); + gl_FragColor.rgb = envMapTexelToLinear(textureCube(envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ))).rgb; + gl_FragColor = linearToOutputTexel(gl_FragColor); +} + `, + + blending: NoBlending, + depthTest: false, + depthWrite: false + + } ); + + shaderMaterial.type = 'CubemapToCubeUV'; + + return shaderMaterial; + + } + + function _getCommonVertexShader() { + + return ` +precision mediump float; +precision mediump int; +attribute vec3 position; +attribute vec2 uv; +attribute float faceIndex; +varying vec3 vOutputDirection; +vec3 getDirection(vec2 uv, float face) { + uv = 2.0 * uv - 1.0; + vec3 direction = vec3(uv, 1.0); + if (face == 0.0) { + direction = direction.zyx; + direction.z *= -1.0; + } else if (face == 1.0) { + direction = direction.xzy; + direction.z *= -1.0; + } else if (face == 3.0) { + direction = direction.zyx; + direction.x *= -1.0; + } else if (face == 4.0) { + direction = direction.xzy; + direction.y *= -1.0; + } else if (face == 5.0) { + direction.xz *= -1.0; + } + return direction; +} +void main() { + vOutputDirection = getDirection(uv, faceIndex); + gl_Position = vec4( position, 1.0 ); +} + `; + + } + + function _getEncodings() { + + return ` +uniform int inputEncoding; +uniform int outputEncoding; + +#include + +vec4 inputTexelToLinear(vec4 value){ + if(inputEncoding == 0){ + return value; + }else if(inputEncoding == 1){ + return sRGBToLinear(value); + }else if(inputEncoding == 2){ + return RGBEToLinear(value); + }else if(inputEncoding == 3){ + return RGBMToLinear(value, 7.0); + }else if(inputEncoding == 4){ + return RGBMToLinear(value, 16.0); + }else if(inputEncoding == 5){ + return RGBDToLinear(value, 256.0); + }else{ + return GammaToLinear(value, 2.2); + } +} + +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); +} + `; + + } + return PMREMGenerator; } )(); diff --git a/examples/textures/equirectangular/pedestrian_overpass_1k.hdr b/examples/textures/equirectangular/pedestrian_overpass_1k.hdr new file mode 100644 index 0000000000000000000000000000000000000000..4d119b90c784cafd83c0cf0bdb226f8a285d1380 Binary files /dev/null and b/examples/textures/equirectangular/pedestrian_overpass_1k.hdr differ diff --git a/examples/textures/equirectangular/pedestrian_overpass_2k.hdr b/examples/textures/equirectangular/pedestrian_overpass_2k.hdr deleted file mode 100644 index c5186617f0524555267680cad759143533587c38..0000000000000000000000000000000000000000 Binary files a/examples/textures/equirectangular/pedestrian_overpass_2k.hdr and /dev/null differ diff --git a/examples/textures/equirectangular/venice_sunset_1k.hdr b/examples/textures/equirectangular/venice_sunset_1k.hdr new file mode 100644 index 0000000000000000000000000000000000000000..048bb13a8bb240ded4609f398fc10c7b4d049a73 Binary files /dev/null and b/examples/textures/equirectangular/venice_sunset_1k.hdr differ diff --git a/examples/textures/equirectangular/venice_sunset_2k.hdr b/examples/textures/equirectangular/venice_sunset_2k.hdr deleted file mode 100644 index eb3cfc5f95bf1df79a379635eecb6817a095ddaa..0000000000000000000000000000000000000000 Binary files a/examples/textures/equirectangular/venice_sunset_2k.hdr and /dev/null differ diff --git a/examples/webgl_furnace_test.html b/examples/webgl_furnace_test.html index efd0d68bec3b44c242350f672f1656503a3ca1fc..b62f5a1ffaaba06f7b0f76fe36a2ae9eac081e8d 100644 --- a/examples/webgl_furnace_test.html +++ b/examples/webgl_furnace_test.html @@ -29,7 +29,6 @@ import * as THREE from '../build/three.module.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var scene, camera, renderer, envMap, radianceMap; var right = 8; @@ -75,8 +74,8 @@ // camera - camera = new THREE.OrthographicCamera( - right, right, right / aspect, - right / aspect, 1, 30 ); - camera.position.set( 0, 0, 9 ); + camera = new THREE.PerspectiveCamera( 40, aspect, 1, 30 ); + camera.position.set( 0, 0, 18 ); } @@ -110,34 +109,16 @@ function createEnvironment() { - var envScene = new THREE.Scene(); - envScene.background = new THREE.Color( 0xcccccc ); - - var cubeCamera = new THREE.CubeCamera( 1, 100, 256, 256 ); - cubeCamera.update( renderer, envScene ); - - envMap = cubeCamera.renderTarget.texture; - - scene.background = envScene.background; - - } - - function getRadiance() { - return new Promise( function ( resolve ) { - var pmremGenerator = new PMREMGenerator( envMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - var cubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var envScene = new THREE.Scene(); + envScene.background = new THREE.Color( 0xcccccc ); + var pmremGenerator = new PMREMGenerator( renderer ); + radianceMap = pmremGenerator.fromScene( envScene ).texture; pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - radianceMap = cubeRenderTarget.texture; + scene.background = radianceMap; resolve(); @@ -147,11 +128,13 @@ function onResize() { - var aspect = window.innerWidth / window.innerHeight; - camera.top = right / aspect; - camera.bottom = - camera.top; + var width = window.innerWidth; + var height = window.innerHeight; + + camera.aspect = width / height; camera.updateProjectionMatrix(); - renderer.setSize( window.innerWidth, window.innerHeight ); + + renderer.setSize( width, height ); } @@ -170,7 +153,6 @@ Promise.resolve() .then( init ) .then( createEnvironment ) - .then( getRadiance ) .then( createObjects ) .then( animate ); diff --git a/examples/webgl_loader_gltf.html b/examples/webgl_loader_gltf.html index 1c7128ca1c57d5515951749695ef74e240c8222f..d4ec89e569904e5a14bf185167a8661e7466eaf0 100644 --- a/examples/webgl_loader_gltf.html +++ b/examples/webgl_loader_gltf.html @@ -25,7 +25,6 @@ import { GLTFLoader } from './jsm/loaders/GLTFLoader.js'; import { RGBELoader } from './jsm/loaders/RGBELoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var container, stats, controls; var camera, scene, renderer; @@ -46,22 +45,13 @@ new RGBELoader() .setDataType( THREE.UnsignedByteType ) .setPath( 'textures/equirectangular/' ) - .load( 'pedestrian_overpass_2k.hdr', function ( texture ) { + .load( 'pedestrian_overpass_1k.hdr', function ( texture ) { - var options = { - minFilter: texture.minFilter, - magFilter: texture.magFilter - }; - - scene.background = new THREE.WebGLRenderTargetCube( 1024, 1024, options ).fromEquirectangularTexture( renderer, texture ); - - var pmremGenerator = new PMREMGenerator( scene.background.texture ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); + var pmremGenerator = new PMREMGenerator( renderer ); + var envMap = pmremGenerator.fromEquirectangular( texture ).texture; + pmremGenerator.dispose(); - var envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; + scene.background = envMap; // model @@ -82,9 +72,6 @@ } ); - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); renderer = new THREE.WebGLRenderer( { antialias: true } ); diff --git a/examples/webgl_loader_gltf_extensions.html b/examples/webgl_loader_gltf_extensions.html index b277e3f45f621a8364cd2cab8111b79756769e95..b1d4b30c11767baab5ca72cd8ce0ef4c20e40ebe 100644 --- a/examples/webgl_loader_gltf_extensions.html +++ b/examples/webgl_loader_gltf_extensions.html @@ -27,7 +27,6 @@ import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'; import { RGBELoader } from './jsm/loaders/RGBELoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var orbitControls; var container, camera, scene, renderer, loader; @@ -156,25 +155,13 @@ new RGBELoader() .setDataType( THREE.UnsignedByteType ) .setPath( 'textures/equirectangular/' ) - .load( 'venice_sunset_2k.hdr', function ( texture ) { - - var options = { - minFilter: texture.minFilter, - magFilter: texture.magFilter - }; - - background = new THREE.WebGLRenderTargetCube( 1024, 1024, options ).fromEquirectangularTexture( renderer, texture ); - - var pmremGenerator = new PMREMGenerator( background.texture ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; + .load( 'venice_sunset_1k.hdr', function ( texture ) { + var pmremGenerator = new PMREMGenerator( renderer ); + envMap = pmremGenerator.fromEquirectangular( texture ).texture; pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); + + background = envMap; // diff --git a/examples/webgl_materials_cars.html b/examples/webgl_materials_cars.html index d3f2e5d9de6d43d90e438deba5020c29a07877ab..e3b1588aa2e828ee63a3ed28db6a0ed5d7a38541 100644 --- a/examples/webgl_materials_cars.html +++ b/examples/webgl_materials_cars.html @@ -43,7 +43,6 @@ import { RGBELoader } from './jsm/loaders/RGBELoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var camera, scene, renderer; var stats, carModel, materialsLib, envMap; @@ -92,20 +91,11 @@ magFilter: texture.magFilter }; - scene.background = new THREE.WebGLRenderTargetCube( 1024, 1024, options ).fromEquirectangularTexture( renderer, texture ); - - envMap = scene.background; - - var pmremGenerator = new PMREMGenerator( scene.background.texture ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; - + var pmremGenerator = new PMREMGenerator( renderer ); + envMap = pmremGenerator.fromEquirectangular( texture ).texture; pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); + + scene.background = envMap; // diff --git a/examples/webgl_materials_envmaps_exr.html b/examples/webgl_materials_envmaps_exr.html index 479884a05125679f9a10e688957f826fc6123521..5fec0e2280ac916f8fce65ebea6152093d38c336 100644 --- a/examples/webgl_materials_envmaps_exr.html +++ b/examples/webgl_materials_envmaps_exr.html @@ -21,7 +21,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { EXRLoader } from './jsm/loaders/EXRLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var params = { envMap: 'EXR', @@ -73,6 +72,13 @@ planeMesh.rotation.x = - Math.PI * 0.5; scene.add( planeMesh ); + var pmremGenerator = new PMREMGenerator( renderer ); + THREE.DefaultLoadingManager.onLoad = function ( ) { + + pmremGenerator.dispose(); + + } + new EXRLoader() .setDataType( THREE.FloatType ) .load( 'textures/piz_compressed.exr', function ( texture ) { @@ -83,19 +89,11 @@ magFilter: THREE.LinearFilter }; - exrBackground = new THREE.WebGLRenderTargetCube( 512, 512, options ).fromEquirectangularTexture( renderer, texture ); + exrCubeRenderTarget = pmremGenerator.fromEquirectangular( texture ); - var pmremGenerator = new PMREMGenerator( exrBackground.texture ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - exrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + exrBackground = exrCubeRenderTarget.texture; texture.dispose(); - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); } ); @@ -103,19 +101,11 @@ texture.encoding = THREE.sRGBEncoding; - pngBackground = new THREE.WebGLRenderTargetCube( 512, 512 ).fromEquirectangularTexture( renderer, texture ); - - var pmremGenerator = new PMREMGenerator( pngBackground.texture ); - pmremGenerator.update( renderer ); + pngCubeRenderTarget = pmremGenerator.fromEquirectangular( texture ); - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - pngCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + pngBackground = pngCubeRenderTarget.texture; texture.dispose(); - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); } ); diff --git a/examples/webgl_materials_envmaps_hdr.html b/examples/webgl_materials_envmaps_hdr.html index 3c6a968f0547c77621245badc0b0ee95787b8bc4..059c44b1dfbb5ef164bbd8b33807c3b07a8c46b9 100644 --- a/examples/webgl_materials_envmaps_hdr.html +++ b/examples/webgl_materials_envmaps_hdr.html @@ -24,7 +24,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var params = { envMap: 'HDR', @@ -78,27 +77,24 @@ planeMesh.rotation.x = - Math.PI * 0.5; scene.add( planeMesh ); - var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ]; + var pmremGenerator = new PMREMGenerator( renderer ); + THREE.DefaultLoadingManager.onLoad = function ( ) { + + pmremGenerator.dispose(); + + } + var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ]; hdrCubeMap = new HDRCubeTextureLoader() .setPath( './textures/cube/pisaHDR/' ) .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function () { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); hdrCubeMap.magFilter = THREE.LinearFilter; hdrCubeMap.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); var ldrUrls = [ 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' ]; @@ -106,18 +102,9 @@ .setPath( './textures/cube/pisa/' ) .load( ldrUrls, function () { - ldrCubeMap.encoding = THREE.sRGBEncoding; - - var pmremGenerator = new PMREMGenerator( ldrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - ldrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + ldrCubeMap.encoding = THREE.GammaEncoding; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); + ldrCubeRenderTarget = pmremGenerator.fromCubemap( ldrCubeMap ); } ); @@ -130,20 +117,11 @@ rgbmCubeMap.encoding = THREE.RGBM16Encoding; rgbmCubeMap.format = THREE.RGBAFormat; - var pmremGenerator = new PMREMGenerator( rgbmCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - rgbmCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + rgbmCubeRenderTarget = pmremGenerator.fromCubemap( rgbmCubeMap ); rgbmCubeMap.magFilter = THREE.LinearFilter; rgbmCubeMap.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); renderer.setPixelRatio( window.devicePixelRatio ); diff --git a/examples/webgl_materials_envmaps_hdr_nodes.html b/examples/webgl_materials_envmaps_hdr_nodes.html index cf23585bcb69bb6f579c990e02b5256d223eebb8..4c573ed831476fc1e4e5c002cfff69723c1b96bf 100644 --- a/examples/webgl_materials_envmaps_hdr_nodes.html +++ b/examples/webgl_materials_envmaps_hdr_nodes.html @@ -41,7 +41,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; import { MeshStandardNodeMaterial } from './jsm/nodes/Nodes.js'; var params = { @@ -103,26 +102,24 @@ planeMesh.rotation.x = - Math.PI * 0.5; scene.add( planeMesh ); + var pmremGenerator = new PMREMGenerator( renderer ); + THREE.DefaultLoadingManager.onLoad = function ( ) { + + pmremGenerator.dispose(); + + } + var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ]; hdrCubeMap = new HDRCubeTextureLoader() .setPath( './textures/cube/pisaHDR/' ) .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function () { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); hdrCubeMap.magFilter = THREE.LinearFilter; hdrCubeMap.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); var ldrUrls = [ 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' ]; @@ -132,16 +129,7 @@ ldrCubeMap.encoding = THREE.GammaEncoding; - var pmremGenerator = new PMREMGenerator( ldrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - ldrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; - - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); + ldrCubeRenderTarget = pmremGenerator.fromCubemap( ldrCubeMap ); } ); @@ -154,20 +142,11 @@ rgbmCubeMap.encoding = THREE.RGBM16Encoding; rgbmCubeMap.format = THREE.RGBAFormat; - var pmremGenerator = new PMREMGenerator( rgbmCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - rgbmCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + rgbmCubeRenderTarget = pmremGenerator.fromCubemap( rgbmCubeMap ); rgbmCubeMap.magFilter = THREE.LinearFilter; rgbmCubeMap.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); renderer.setPixelRatio( window.devicePixelRatio ); diff --git a/examples/webgl_materials_envmaps_pmrem_nodes.html b/examples/webgl_materials_envmaps_pmrem_nodes.html index 34269918e671773fc8f709dc85aef9720f4047dd..f196d14e96513dde397a7e1cd057deb92b35ba6e 100644 --- a/examples/webgl_materials_envmaps_pmrem_nodes.html +++ b/examples/webgl_materials_envmaps_pmrem_nodes.html @@ -41,7 +41,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; import { StandardNodeMaterial, @@ -74,13 +73,10 @@ nodeTextureSize.value = textureSize; - var pmremGenerator = new PMREMGenerator( hdrCubeMap, undefined, textureSize / 4 ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); + var pmremGenerator = new PMREMGenerator( renderer ); + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; nodeTexture.value = hdrCubeRenderTarget.texture; hdrCubeMap.magFilter = THREE.LinearFilter; @@ -89,9 +85,6 @@ planeMesh.material.map = hdrCubeRenderTarget.texture; planeMesh.material.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } function init() { diff --git a/examples/webgl_materials_nodes.html b/examples/webgl_materials_nodes.html index 89f0256e472c81df81c51f5b173caca7722a2fd1..1bd3ac6203bb08637d4d284dc9a8e61e6ef5ce0d 100644 --- a/examples/webgl_materials_nodes.html +++ b/examples/webgl_materials_nodes.html @@ -24,7 +24,6 @@ import { TeapotBufferGeometry } from './jsm/geometries/TeapotBufferGeometry.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; import { NodeMaterialLoader, NodeMaterialLoaderUtils } from './jsm/loaders/NodeMaterialLoader.js'; @@ -70,7 +69,7 @@ } - var premTexture, pmremCube, pmremGenerator, pmremCubeUVPacker, premSize = 1024; + var premTexture, pmremCube, pmremGenerator, premSize = 1024; function updatePREM( textureCube ) { @@ -82,24 +81,17 @@ var magFilter = pmremCube.magFilter; var generateMipmaps = pmremCube.generateMipmaps; - pmremGenerator = new PMREMGenerator( pmremCube, undefined, premSize / 4 ); - pmremGenerator.update( renderer ); - - pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); + var pmremGenerator = new PMREMGenerator( renderer ); + premTexture = pmremGenerator.fromCubemap( pmremCube ).texture; + pmremGenerator.dispose(); pmremCube.minFilter = minFilter; pmremCube.magFilter = magFilter; pmremCube.generateMipmaps = generateMipmaps; pmremCube.needsUpdate = true; - premTexture = pmremCubeUVPacker.CubeUVRenderTarget.texture; - library[ premTexture.uuid ] = premTexture; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } var cubemap = function () { diff --git a/examples/webgl_materials_physical_clearcoat.html b/examples/webgl_materials_physical_clearcoat.html index 80447eb4133e3930b962dc4fc945062c6101cbaa..f41cf07da55a5a218230fa577a9fb8025e091f58 100644 --- a/examples/webgl_materials_physical_clearcoat.html +++ b/examples/webgl_materials_physical_clearcoat.html @@ -22,7 +22,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var container, stats; @@ -53,13 +52,9 @@ .load( [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ], function ( hdrCubeMap ) { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - var hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + var hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); var geometry = new THREE.SphereBufferGeometry( 80, 64, 32 ); @@ -160,9 +155,6 @@ hdrCubeMap.needsUpdate = true; scene.background = hdrCubeMap; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); diff --git a/examples/webgl_materials_physical_transparency.html b/examples/webgl_materials_physical_transparency.html index ac6aead821ff99d6c4a1628e34f512b01ebdf97a..90efbde66429b1f0e00972e675448b57036b85c7 100644 --- a/examples/webgl_materials_physical_transparency.html +++ b/examples/webgl_materials_physical_transparency.html @@ -21,7 +21,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var params = { color: 0xffffff, @@ -74,20 +73,13 @@ // - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); hdrCubeMap.magFilter = THREE.LinearFilter; hdrCubeMap.needsUpdate = true; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - // var geometry = new THREE.SphereBufferGeometry( 20, 64, 32 ); diff --git a/examples/webgl_materials_reflectivity.html b/examples/webgl_materials_reflectivity.html index 5a05ee5f54e55765c3e50d900bf42411d832215a..d31c9d78ec1fa922709f9c19c60e9507b805b114 100644 --- a/examples/webgl_materials_reflectivity.html +++ b/examples/webgl_materials_reflectivity.html @@ -25,7 +25,6 @@ import { OBJLoader } from './jsm/loaders/OBJLoader.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var container, stats; var params = { @@ -129,20 +128,14 @@ .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function ( hdrCubeMap ) { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); gemFrontMaterial.envMap = gemBackMaterial.envMap = hdrCubeRenderTarget.texture; gemFrontMaterial.needsUpdate = gemBackMaterial.needsUpdate = true; hdrCubeMap.dispose(); - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); } ); diff --git a/examples/webgl_materials_standard.html b/examples/webgl_materials_standard.html index 572746b43c09dc9134a9aa715b22e4420244c0c6..91379f4bf56c518bdda1e6b724747dac9ad8cc0f 100644 --- a/examples/webgl_materials_standard.html +++ b/examples/webgl_materials_standard.html @@ -22,7 +22,6 @@ import { TrackballControls } from './jsm/controls/TrackballControls.js'; import { OBJLoader } from './jsm/loaders/OBJLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var statsEnabled = true; @@ -107,13 +106,9 @@ rgbmCubeMap.encoding = THREE.RGBM16Encoding; rgbmCubeMap.format = THREE.RGBAFormat; - var pmremGenerator = new PMREMGenerator( rgbmCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - var rgbmCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + var rgbmCubeRenderTarget = pmremGenerator.fromCubemap( rgbmCubeMap ); + pmremGenerator.dispose(); material.envMap = rgbmCubeRenderTarget.texture; material.needsUpdate = true; // is this needed? @@ -122,9 +117,6 @@ rgbmCubeMap.needsUpdate = true; scene.background = rgbmCubeMap; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); // diff --git a/examples/webgl_materials_variations_physical.html b/examples/webgl_materials_variations_physical.html index 8773a7e42942eaa9e389b0b34ff3ec0ec8e6f73f..ec1d76574e9d306d5bb27339d1c721e2bd5bc190 100644 --- a/examples/webgl_materials_variations_physical.html +++ b/examples/webgl_materials_variations_physical.html @@ -21,7 +21,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var container, stats; @@ -65,13 +64,9 @@ .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function ( hdrCubeMap ) { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); // Materials @@ -124,9 +119,6 @@ hdrCubeMap.needsUpdate = true; scene.background = hdrCubeMap; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); function addLabel( name, location ) { diff --git a/examples/webgl_materials_variations_standard.html b/examples/webgl_materials_variations_standard.html index cae166b4796439897c943cfc1669e3c0fc72aefa..513291a1e91e9a989240c5f0f39e07ea4582e8d0 100644 --- a/examples/webgl_materials_variations_standard.html +++ b/examples/webgl_materials_variations_standard.html @@ -21,7 +21,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; var container, stats; @@ -71,13 +70,9 @@ .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function ( hdrCubeMap ) { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; + var pmremGenerator = new PMREMGenerator( renderer ); + hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap ); + pmremGenerator.dispose(); var bumpScale = 1; var cubeWidth = 400; @@ -130,9 +125,6 @@ hdrCubeMap.needsUpdate = true; scene.background = hdrCubeMap; - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - } ); function addLabel( name, location ) { diff --git a/examples/webgl_tonemapping.html b/examples/webgl_tonemapping.html index 5c787f89f1787ca5dbacefe1349a9f44c5c0d682..15bdd61b883430700e3f9b63c4722240d4d4c026 100644 --- a/examples/webgl_tonemapping.html +++ b/examples/webgl_tonemapping.html @@ -21,7 +21,6 @@ import { OrbitControls } from './jsm/controls/OrbitControls.js'; import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; import { EffectComposer } from './jsm/postprocessing/EffectComposer.js'; import { RenderPass } from './jsm/postprocessing/RenderPass.js'; @@ -146,18 +145,12 @@ .setDataType( THREE.UnsignedByteType ) .load( hdrUrls, function ( hdrCubeMap ) { - var pmremGenerator = new PMREMGenerator( hdrCubeMap ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - standardMaterial.envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; + var pmremGenerator = new PMREMGenerator( renderer ); + standardMaterial.envMap = pmremGenerator.fromCubemap( hdrCubeMap ).texture; standardMaterial.needsUpdate = true; hdrCubeMap.dispose(); pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); } ); diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index c62b560805636136fc357910f472a643680eba4f..c1387bc61eae8d69e20a86f2547d8620669132f2 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1990,6 +1990,10 @@ function WebGLRenderer( parameters ) { m_uniforms.color.value.copy( material.color ); m_uniforms.opacity.value = material.opacity; + } else if ( material.envMap ) { + + refreshUniformsCommon( m_uniforms, material ); + } // RectAreaLight Texture 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 ca8711068ea14af02fa1504a9ae2963819b2f391..e505502c9f1d675a995f5df6bea8bded8e8b8e4c 100644 --- a/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js @@ -1,130 +1,160 @@ export default /* glsl */` #ifdef ENVMAP_TYPE_CUBE_UV -#define cubeUV_textureSize (1024.0) - -int getFaceFromDirection(vec3 direction) { - vec3 absDirection = abs(direction); - int face = -1; - if( absDirection.x > absDirection.z ) { - if(absDirection.x > absDirection.y ) - face = direction.x > 0.0 ? 0 : 3; - else - face = direction.y > 0.0 ? 1 : 4; - } - else { - if(absDirection.z > absDirection.y ) - face = direction.z > 0.0 ? 2 : 5; - else - face = direction.y > 0.0 ? 1 : 4; - } - return face; +#define cubeUV_maxMipLevel 8.0 +#define cubeUV_minMipLevel 4.0 +#define cubeUV_maxTileSize 256.0 +#define cubeUV_minTileSize 16.0 + +// These shader functions convert between the UV coordinates of a single face of +// a cubemap, the 0-5 integer index of a cube face, and the direction vector for +// sampling a textureCube (not generally normalized). + +float getFace(vec3 direction) { + vec3 absDirection = abs(direction); + float face = -1.0; + if (absDirection.x > absDirection.z) { + if (absDirection.x > absDirection.y) + face = direction.x > 0.0 ? 0.0 : 3.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } else { + if (absDirection.z > absDirection.y) + face = direction.z > 0.0 ? 2.0 : 5.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } + return face; } -#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0) -#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0)) -vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) { - float scale = exp2(cubeUV_maxLods1 - roughnessLevel); - float dxRoughness = dFdx(roughness); - float dyRoughness = dFdy(roughness); - vec3 dx = dFdx( vec * scale * dxRoughness ); - vec3 dy = dFdy( vec * scale * dyRoughness ); - float d = max( dot( dx, dx ), dot( dy, dy ) ); - // Clamp the value to the max mip level counts. hard coded to 6 mips - d = clamp(d, 1.0, cubeUV_rangeClamp); - float mipLevel = 0.5 * log2(d); - return vec2(floor(mipLevel), fract(mipLevel)); +vec2 getUV(vec3 direction, float face) { + vec2 uv; + if (face == 0.0) { + uv = vec2(-direction.z, direction.y) / abs(direction.x); + } else if (face == 1.0) { + uv = vec2(direction.x, -direction.z) / abs(direction.y); + } else if (face == 2.0) { + uv = direction.xy / abs(direction.z); + } else if (face == 3.0) { + uv = vec2(direction.z, direction.y) / abs(direction.x); + } else if (face == 4.0) { + uv = direction.xz / abs(direction.y); + } else { + uv = vec2(-direction.x, direction.y) / abs(direction.z); + } + return 0.5 * (uv + 1.0); } -#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0) -#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize) - -vec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) { - mipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel; - float a = 16.0 * cubeUV_rcpTextureSize; - - vec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) ); - vec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed; - // float powScale = exp2(roughnessLevel + mipLevel); - float powScale = exp2_packed.x * exp2_packed.y; - // float scale = 1.0 / exp2(roughnessLevel + 2.0 + mipLevel); - float scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25; - // float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel); - float mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x; - - bool bRes = mipLevel == 0.0; - scale = bRes && (scale < a) ? a : scale; - - vec3 r; - vec2 offset; - int face = getFaceFromDirection(direction); - - float rcpPowScale = 1.0 / powScale; - - if( face == 0) { - r = vec3(direction.x, -direction.z, direction.y); - offset = vec2(0.0+mipOffset,0.75 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y; - } - else if( face == 1) { - r = vec3(direction.y, direction.x, direction.z); - offset = vec2(scale+mipOffset, 0.75 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y; - } - else if( face == 2) { - r = vec3(direction.z, direction.x, direction.y); - offset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y; - } - else if( face == 3) { - r = vec3(direction.x, direction.z, direction.y); - offset = vec2(0.0+mipOffset,0.5 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y; - } - else if( face == 4) { - r = vec3(direction.y, direction.x, -direction.z); - offset = vec2(scale+mipOffset, 0.5 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y; - } - else { - r = vec3(direction.z, -direction.x, direction.y); - offset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale); - offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y; - } - r = normalize(r); - float texelOffset = 0.5 * cubeUV_rcpTextureSize; - vec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5; - vec2 base = offset + vec2( texelOffset ); - return base + s * ( scale - 2.0 * texelOffset ); +vec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) { + float face = getFace(direction); + float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0); + mipInt = max(mipInt, cubeUV_minMipLevel); + float faceSize = exp2(mipInt); + + float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize); + + vec2 uv = getUV(direction, face) * (faceSize - 1.0); + vec2 f = fract(uv); + uv += 0.5 - f; + if (face > 2.0) { + uv.y += faceSize; + face -= 3.0; + } + uv.x += face * faceSize; + if(mipInt < cubeUV_maxMipLevel){ + uv.y += 2.0 * cubeUV_maxTileSize; + } + uv.y += filterInt * 2.0 * cubeUV_minTileSize; + uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize); + uv *= texelSize; + + 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); } -#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0) - -vec4 textureCubeUV( sampler2D envMap, vec3 reflectedDirection, float roughness ) { - float roughnessVal = roughness* cubeUV_maxLods3; - float r1 = floor(roughnessVal); - float r2 = r1 + 1.0; - float t = fract(roughnessVal); - vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness); - float s = mipInfo.y; - float level0 = mipInfo.x; - float level1 = level0 + 1.0; - level1 = level1 > 5.0 ? 5.0 : level1; - - // round to nearest mipmap if we are not interpolating. - level0 += min( floor( s + 0.5 ), 5.0 ); - - // Tri linear interpolation. - vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0); - vec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10)); - - vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0); - vec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20)); +// These defines must match with PMREMGenerator + +#define r0 1.0 +#define v0 0.339 +#define m0 -2.0 +#define r1 0.8 +#define v1 0.276 +#define m1 -1.0 +#define r4 0.4 +#define v4 0.046 +#define m4 2.0 +#define r5 0.305 +#define v5 0.016 +#define m5 3.0 +#define r6 0.21 +#define v6 0.0038 +#define m6 4.0 + +float roughnessToVariance(float roughness) { + float variance = 0.0; + if (roughness >= r1) { + variance = (r0 - roughness) * (v1 - v0) / (r0 - r1) + v0; + } else if (roughness >= r4) { + variance = (r1 - roughness) * (v4 - v1) / (r1 - r4) + v1; + } else if (roughness >= r5) { + variance = (r4 - roughness) * (v5 - v4) / (r4 - r5) + v4; + } else { + float roughness2 = roughness * roughness; + variance = 1.79 * roughness2 * roughness2; + } + return variance; +} - vec4 result = mix(color10, color20, t); +float varianceToRoughness(float variance) { + float roughness = 0.0; + if (variance >= v1) { + roughness = (v0 - variance) * (r1 - r0) / (v0 - v1) + r0; + } else if (variance >= v4) { + roughness = (v1 - variance) * (r4 - r1) / (v1 - v4) + r1; + } else if (variance >= v5) { + roughness = (v4 - variance) * (r5 - r4) / (v4 - v5) + r4; + } else { + roughness = pow(0.559 * variance, 0.25);// 0.559 = 1.0 / 1.79 + } + return roughness; +} - return vec4(result.rgb, 1.0); +float roughnessToMip(float roughness) { + float mip = 0.0; + if (roughness >= r1) { + mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0; + } else if (roughness >= r4) { + mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1; + } else if (roughness >= r5) { + mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4; + } else if (roughness >= r6) { + mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5; + } else { + mip = -2.0 * log2(1.16 * roughness);// 1.16 = 1.79^0.25 + } + return mip; } +vec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) { + float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel); + float mipF = fract(mip); + float mipInt = floor(mip); + + vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt); + if (mipF == 0.0) { + return vec4(color0, 1.0); + } else { + vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0); + return vec4(mix(color0, color1, mipF), 1.0); + } +} #endif `; diff --git a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js index 0756f9373136274af32d9273f05a564f854bc4dd..db216edb813f6a86ea24a1edea8523cf9d17be64 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js @@ -38,6 +38,10 @@ export default /* glsl */` vec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + + vec4 envColor = textureCubeUV( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ), 0.0 ); + #elif defined( ENVMAP_TYPE_EQUIREC ) vec2 sampleUV; @@ -64,7 +68,11 @@ export default /* glsl */` #endif - envColor = envMapTexelToLinear( envColor ); + #ifndef ENVMAP_TYPE_CUBE_UV + + envColor = envMapTexelToLinear( envColor ); + + #endif #ifdef ENVMAP_BLENDING_MULTIPLY diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index ccdf6286c527c20ff3dc3efcd5df40539872043d..b53c25ba3239d96e4caa5e818eeccf8945985999 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -236,11 +236,12 @@ var ShaderLib = { cube: { - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, + uniforms: mergeUniforms( [ + UniformsLib.envmap, + { + opacity: { value: 1.0 } + } + ] ), vertexShader: ShaderChunk.cube_vert, fragmentShader: ShaderChunk.cube_frag diff --git a/src/renderers/shaders/ShaderLib/cube_frag.glsl.js b/src/renderers/shaders/ShaderLib/cube_frag.glsl.js index 0a53ba08ec88305c5b15e89e877e702bd6e4c797..9355727295e076c3dead022d82b3ee616727271e 100644 --- a/src/renderers/shaders/ShaderLib/cube_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/cube_frag.glsl.js @@ -1,15 +1,18 @@ export default /* glsl */` -uniform samplerCube tCube; -uniform float tFlip; + +#include uniform float opacity; varying vec3 vWorldDirection; +#include + void main() { - vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + vec3 vReflect = vWorldDirection; + #include - gl_FragColor = mapTexelToLinear( texColor ); + gl_FragColor = envColor; gl_FragColor.a *= opacity; #include diff --git a/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl.js index 18e6c9649c785b49a8ffc168ae368410c5576794..493eaa97881f1cfc82de9d1fadbb75e4553da4b2 100644 --- a/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl.js @@ -18,6 +18,7 @@ uniform float opacity; #include #include #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshlambert_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshlambert_frag.glsl.js index f00305c709b0c91b238ee7474e9a178585bbdb37..ddb9bfce6616512d996d164b5d78b91d1fe3a2b9 100644 --- a/src/renderers/shaders/ShaderLib/meshlambert_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshlambert_frag.glsl.js @@ -25,6 +25,7 @@ varying vec3 vIndirectFront; #include #include #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshphong_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphong_frag.glsl.js index 10ee79e6def63d075215c999665d9a434fde1172..10c82ebc8def302154fc92ac6b5aade4a0871f76 100644 --- a/src/renderers/shaders/ShaderLib/meshphong_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphong_frag.glsl.js @@ -20,6 +20,7 @@ uniform float opacity; #include #include #include +#include #include #include #include diff --git a/src/renderers/webgl/WebGLBackground.js b/src/renderers/webgl/WebGLBackground.js index f9a8c50a637d7b97189ef7a745c1682432c852f2..6d3c5b84d92994a776f954d37c05f97b01604660 100644 --- a/src/renderers/webgl/WebGLBackground.js +++ b/src/renderers/webgl/WebGLBackground.js @@ -2,7 +2,7 @@ * @author mrdoob / http://mrdoob.com/ */ -import { BackSide, FrontSide } from '../../constants.js'; +import { BackSide, FrontSide, CubeUVReflectionMapping } from '../../constants.js'; import { BoxBufferGeometry } from '../../geometries/BoxGeometry.js'; import { PlaneBufferGeometry } from '../../geometries/PlaneGeometry.js'; import { ShaderMaterial } from '../../materials/ShaderMaterial.js'; @@ -60,7 +60,7 @@ function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { } - if ( background && ( background.isCubeTexture || background.isWebGLRenderTargetCube ) ) { + if ( background && ( background.isCubeTexture || background.isWebGLRenderTargetCube || background.mapping === CubeUVReflectionMapping ) ) { if ( boxMesh === undefined ) { @@ -92,7 +92,7 @@ function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { get: function () { - return this.uniforms.tCube.value; + return this.envMap.value; } @@ -103,8 +103,7 @@ function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { } var texture = background.isWebGLRenderTargetCube ? background.texture : background; - boxMesh.material.uniforms.tCube.value = texture; - boxMesh.material.uniforms.tFlip.value = ( background.isWebGLRenderTargetCube ) ? 1 : - 1; + boxMesh.material.envMap = texture; if ( currentBackground !== background || currentBackgroundVersion !== texture.version ) { diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index 7a192887cc00aaf64e548542c59b54f0a46765bf..8800fddd7ea2acc847a65160e9a1d5a15400dceb 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -351,7 +351,7 @@ function generateEnvMapModeDefine( parameters ) { function generateEnvMapBlendingDefine( parameters ) { - var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + var envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; if ( parameters.envMap ) { diff --git a/utils/modularize.js b/utils/modularize.js index df5df64b92a4bb793cd4b3d81bba668070166fb2..628b055953db2b5a076f7ddb5d48a20132977ebd 100644 --- a/utils/modularize.js +++ b/utils/modularize.js @@ -142,7 +142,6 @@ var files = [ { path: 'objects/Water.js', dependencies: [], ignoreList: [] }, { path: 'objects/Water2.js', dependencies: [ { name: 'Reflector', path: 'objects/Reflector.js' }, { name: 'Refractor', path: 'objects/Refractor.js' } ], ignoreList: [] }, - { path: 'pmrem/PMREMCubeUVPacker.js', dependencies: [], ignoreList: [] }, { path: 'pmrem/PMREMGenerator.js', dependencies: [], ignoreList: [] }, { path: 'postprocessing/AdaptiveToneMappingPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' }, { name: 'LuminosityShader', path: 'shaders/LuminosityShader.js' }, { name: 'ToneMapShader', path: 'shaders/ToneMapShader.js' } ], ignoreList: [] },